Npgsql 与实体框架代码集成
Posted
技术标签:
【中文标题】Npgsql 与实体框架代码集成【英文标题】:Npgsql integration with Entity Framework Code First 【发布时间】:2013-03-26 17:28:49 【问题描述】:我有一个项目使用最新版本的 EF CF 与 PostgreSQL 和 Npgsql。
我的模型看起来像:
[Table("mytable")]
public class MyTable
[Column("id")]
public int Id get; set;
[Column("mycolumn")]
public string MyColumn get; set;
并且数据库/表/列的名称为小写,例如:
CREATE TABLE mytable
id serial,
mycolumn character(50)
Npgsql 生成带引号的 SQL 命令,因此由于 PostgreSQL 的特性,我必须使用数据注释,女巫很烦人。但是我不想在数据库中使用引号分隔的名称。
有没有办法将 Npgsql 配置为在生成命令时不包含引号或在生成的 SQL 中强制使用小写表/列名称?
【问题讨论】:
我去看看。 嗨,Francisco,在 EF6 中,可以使用约定来小写表名和列名,而不是为每个人添加一个属性,因此不必太担心这个问题。 :) 使用代码约定是可行的。幸运的是,当 Postgres 看到列名都是小写时,它会忽略双引号(所以我们仍然会在查询时得到大小写折叠),但知道如何关闭双引号仍然会很好。 【参考方案1】:如果我没有遗漏什么 - 你想要一些通用的方式of changing the naming convention for tables
?
EF6 有custom conventions
功能 - 它还不是正式版本,但如果它适合你,一些链接...
http://entityframework.codeplex.com/wikipage?title=Custom%20Conventions
在你的情况下,你必须为类/Type
我猜 - 例如(一些伪代码)...
1) 实现IConfigurationConvention<Type, EntityTypeConfiguration>
(可以查看EntityConventionBase
的EF源)
2) 在Apply
- 通过配置 (ToTable()
) 更改表名称的生成方式 - 类似于 .ToLowerCase()
3) 加入约定...
例如……
public class SmallCapsEntitiesConfigurationConvention
: IConfigurationConvention<Type, EntityTypeConfiguration>
public void Apply(Type memberInfo, Func<EntityTypeConfiguration> configuration)
configuration().ToTable(memberInfo.Name.ToLowerInvariant(), null);
你可以在这里看到一个例子http://blog.cincura.net/233167-custom-conventions-in-entity-framework-6-helping-firebird/
否则,我不知道 Npgsql
/ PostgreSQL - 我觉得它确实有点“原始”。但是你可以在 EF 端处理它。
【讨论】:
这是解决我问题的好方法!但是 EF6 的发布并不稳定,我不能在我的公司使用这个版本。但无论如何我都会记住这一点。 我知道@MaxBündchen - 但这是我认为你得到的最好的 - 在 PostgreSQL 方面没有任何解决方案 嘿,我也有同样的问题......现在 EF6 出来了! :D【参考方案2】:这是 EF Core 的示例。
当前代码将tables
、properties
、keys
和indexes
转换为Postgre
的snake case,您可以将其用作自定义约定的基础:
using System;
using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql;
namespace Database.Customization
public class PostgreDbContext : DbContext
private static readonly Regex _keysRegex = new Regex("^(PK|FK|IX)_", RegexOptions.Compiled);
public PostgreDbContext(DbContextOptions options)
: base(options)
protected override void OnModelCreating(ModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
FixSnakeCaseNames(modelBuilder);
private void FixSnakeCaseNames(ModelBuilder modelBuilder)
var mapper = new NpgsqlSnakeCaseNameTranslator();
foreach (var table in modelBuilder.Model.GetEntityTypes())
ConvertToSnake(mapper, table);
foreach (var property in table.GetProperties())
ConvertToSnake(mapper, property);
foreach (var primaryKey in table.GetKeys())
ConvertToSnake(mapper, primaryKey);
foreach (var foreignKey in table.GetForeignKeys())
ConvertToSnake(mapper, foreignKey);
foreach (var indexKey in table.GetIndexes())
ConvertToSnake(mapper, indexKey);
private void ConvertToSnake(INpgsqlNameTranslator mapper, object entity)
switch (entity)
case IMutableEntityType table:
var relationalTable = table.Relational();
relationalTable.TableName = ConvertGeneralToSnake(mapper, relationalTable.TableName);
if (relationalTable.TableName.StartsWith("asp_net_"))
relationalTable.TableName = relationalTable.TableName.Replace("asp_net_", string.Empty);
relationalTable.Schema = "identity";
break;
case IMutableProperty property:
property.Relational().ColumnName = ConvertGeneralToSnake(mapper, property.Relational().ColumnName);
break;
case IMutableKey primaryKey:
primaryKey.Relational().Name = ConvertKeyToSnake(mapper, primaryKey.Relational().Name);
break;
case IMutableForeignKey foreignKey:
foreignKey.Relational().Name = ConvertKeyToSnake(mapper, foreignKey.Relational().Name);
break;
case IMutableIndex indexKey:
indexKey.Relational().Name = ConvertKeyToSnake(mapper, indexKey.Relational().Name);
break;
default:
throw new NotImplementedException("Unexpected type was provided to snake case converter");
private string ConvertKeyToSnake(INpgsqlNameTranslator mapper, string keyName) =>
ConvertGeneralToSnake(mapper, _keysRegex.Replace(keyName, match => match.Value.ToLower()));
private string ConvertGeneralToSnake(INpgsqlNameTranslator mapper, string entityName) =>
mapper.TranslateMemberName(ModifyNameBeforeConvertion(mapper, entityName));
protected virtual string ModifyNameBeforeConvertion(INpgsqlNameTranslator mapper, string entityName) => entityName;
更新:
如果您使用的是 EF 核心 3,那么 Relational()
将导致错误,因为该方法最近已被删除。修改ConvertToSnake
函数的定义如下:
private void ConvertToSnake(INpgsqlNameTranslator mapper, object entity)
switch (entity)
case IMutableEntityType table:
table.SetTableName(ConvertGeneralToSnake(mapper, table.GetTableName()));
if (table.GetTableName().StartsWith("asp_net_"))
table.SetTableName(table.GetTableName().Replace("asp_net_", string.Empty));
table.SetSchema("identity");
break;
case IMutableProperty property:
property.SetColumnName(ConvertGeneralToSnake(mapper, property.GetColumnName()));
break;
case IMutableKey primaryKey:
primaryKey.SetName(ConvertKeyToSnake(mapper, primaryKey.GetName()));
break;
case IMutableForeignKey foreignKey:
foreignKey.SetConstraintName(ConvertKeyToSnake(mapper, foreignKey.GetConstraintName()));
break;
case IMutableIndex indexKey:
indexKey.SetName(ConvertKeyToSnake(mapper, indexKey.GetName()));
break;
default:
throw new NotImplementedException("Unexpected type was provided to snake case converter");
【讨论】:
github.com/npgsql/efcore.pg/issues/21#issuecomment-376114368以上是关于Npgsql 与实体框架代码集成的主要内容,如果未能解决你的问题,请参考以下文章
npgsql 和 Entity Framework 代码第一次设置问题
Entity Framework 5.0 PostgreSQL (Npgsql) 默认连接工厂
ASP.NET MVC 使用 Petapoco 微型ORM框架+NpgSql驱动连接 PostgreSQL数据库(问题总结)