使用Entity Framework Code First集成Npgsql

8
我正在使用最新版本的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,在生成命令时不包括引号,或者强制使用小写表/列名称?

我会看一下。 - Francisco Junior
1
嗨,Francisco,在EF6中,可以使用约定来将表和列名转换为小写,而不必为每个表和列添加属性,因此不用太担心这个问题。 :) - Max Bündchen
使用代码约定是有效的。幸运的是,当Postgres看到列名全部小写时,它会忽略双引号(因此我们仍然在查询时获得大小写折叠),但了解如何关闭双引号仍然很好。 - jhexp
2个回答

8
如果我没有理解错的话 - 你想要一种通用的方式来改变表格的命名规范?EF6有自定义约定功能 - 这还不是官方版本,但如果它适合你,这里有一些链接...

http://entityframework.codeplex.com/wikipage?title=Custom%20Conventions

在您的情况下,我想您需要为类/Type实现它-例如(一些伪代码)...
1)实现IConfigurationConvention<Type, EntityTypeConfiguration>(您可以检查EF源代码中的EntityConventionBase
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还没有发布为稳定版本,我不能在公司使用这个版本。但无论如何,我会记住这个方法的。 - Max Bündchen
2
我知道@MaxBündchen - 但我认为这是最好的选择 - 除非有关于PostgreSQL方面的解决方案。 - NSGaga-mostly-inactive
1
嘿,我也有同样的问题... 而且EF6现在已经发布了! :D - C. Tewalt

2
这是一个关于EF Core的示例。
当前代码将Postgre中的tablespropertieskeysindexes转换为蛇形命名,您可以将其用作自定义约定的基础。
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");
    }
}

https://github.com/npgsql/efcore.pg/issues/21#issuecomment-376114368 - Rahatur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接