Entity framework 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 {

我有一个项目使用了最新版本的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
{
    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看到列名都是小写时,它会忽略双引号(因此我们在查询时仍会进行大小写折叠),但知道如何关闭双引号还是不错的。