Entity framework Npgsql首先与实体框架代码集成
我有一个项目使用了最新版本的EFCF和PostgreSQL和Npgsql 我的模型看起来像:Entity framework Npgsql首先与实体框架代码集成,entity-framework,npgsql,Entity Framework,Npgsql,我有一个项目使用了最新版本的EFCF和PostgreSQL和Npgsql 我的模型看起来像: [Table("mytable")] public class MyTable { [Column("id")] public int Id { get; set; } [Column("mycolumn")] public string MyColumn { get; set; } } 数据库/表/列有小写名称,如: CREATE TABLE mytable {
[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中强制使用小写的表/列名称?如果我没有遗漏什么,您可能需要一些通用的方法来更改表的命名约定 EF6有
自定义约定
功能-它仍然不是官方版本,但是如果它适合你,一些链接
在您的情况下,您必须为类/类型
实现它,我猜-例如(一些伪代码)
1) 实施IConfigurationConvention
(您可以检查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);
}
}
公共类小容量配置约定
:IConfigurationConvention
{
公共无效应用(类型memberInfo,Func配置)
{
configuration().ToTable(memberInfo.Name.ToLowerInvariant(),null);
}
}
您可以在这里看到一个示例否则,我对
Npgsql
/PostgreSQL一无所知——对我来说,它确实有点“原始”。但是您可以在EF端处理它。这里是EF Core的一个示例
当前代码将表
、属性
、键
和索引
转换为Postgre
的蛇形格,您可以将其用作自定义约定的基础:
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 core 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");
}
}
这是解决我问题的好办法!然而,EF6的发布并不稳定,我不能在我的公司上使用这个版本。但无论如何,我会记住这一点。我知道@MaxBündchen——但我认为这是你得到的最好的答案——在PostgreSQL方面没有任何解决方案。嘿,我也有同样的问题。。。EF6现在已经出来了!:我来看看。嗨,Francisco,在EF6中,可以使用约定来降低表名和列名的大小写,而不是为每个表名和列名添加一个属性,所以不用太担心这个问题。:)使用代码约定是可行的。幸运的是,当Postgres看到列名都是小写时,它会忽略双引号(因此我们在查询时仍会进行大小写折叠),但知道如何关闭双引号还是不错的。