【问题标题】:Using Singular Table Names with EF Core 2在 EF Core 2 中使用单一表名称
【发布时间】:2018-03-11 21:14:06
【问题描述】:

我希望我的域类名与我的 db 表名相匹配(没有复数形式)。

在 EF Core 1.1 中,我使用以下代码来执行此操作:

public static void RemovePluralisingTableNameConvention(this ModelBuilder modelBuilder)
{
    foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
    {
        entityType.Relational().TableName = entityType.DisplayName();
    }
}

在 EF Core 2.0 中,此代码无法编译,因为 Relational() 不是 IMutableEntityType 上的方法。 无论如何,在 EF Core 2.0 中,他们添加了 IPluralizer,记录在这里:

https://github.com/aspnet/EntityFramework.Docs/blob/master/entity-framework/core/what-is-new/index.md#pluralization-hook-for-dbcontext-scaffolding

没有太多示例可以展示如何实现与我以前相同的行为。关于如何在 EF Core 2 中删除复数的任何线索?

【问题讨论】:

  • EF Core 2.0 的约定是对表使用 DbSet 的名称。如果您从未为表指定 DbSet,则 EF Core 将使用类名作为表名。显然,如果您在 Fluent 映射中使用 ToTable 指定表名,这一切都会被忽略。

标签: c# ef-code-first entity-framework-core


【解决方案1】:

您可以通过使用ClrType.Name 来执行此操作,而无需使用内部 EF API 调用

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        // Use the entity name instead of the Context.DbSet<T> name
        // refs https://docs.microsoft.com/en-us/ef/core/modeling/entity-types?tabs=fluent-api#table-name
        modelBuilder.Entity(entityType.ClrType).ToTable(entityType.ClrType.Name);
    }
}

【讨论】:

  • 谢谢!对于任何寻找小写表名的人.ToTable(entityType.ClrType.Name.ToLower())
【解决方案2】:

您可以使用完全相同的代码。 Relational() 是在 Microsoft.EntityFrameworkCore.Relational.dll assembly 内的 RelationalMetadataExtensions 类中定义的 extension 方法,因此请确保引用它。

IPluralizer呢,从链接可以看出它只是一个DbContext Scaffolding的复数钩子,即从数据库中生成实体类,用于实体类型名称的单数化和复数化数据库集名称。它不用于表名生成。默认表名称约定在文档的Table Mapping 部分进行了说明:

按照惯例,每个实体都将设置为映射到与DbSet&lt;TEntity&gt; 属性同名的表,该属性在派生上下文中公开实体。如果给定实体没有包含DbSet&lt;TEntity&gt;,则使用类名。

【讨论】:

  • Relational() 是内部命名空间的一部分,在后续版本中可能不再可用。
  • @Matthieu 不。如果您点击该链接,您会看到它是 public API 的一部分。但这并不能阻止他们在 3.0 中将其作为“重大更改”删除 :)
【解决方案3】:

如果有人想在 .NET Core 3.1 中尝试,您可以将扩展方法构建为

public static class ModelBuilderExtension
{
    /// <summary>
    /// Remove pluralizing table name convention to create table name in singular form.
    /// </summary>       
    public static void RemovePluralizingTableNameConvention(this ModelBuilder modelBuilder)
    {
        foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
        {
            entityType.SetTableName(entityType.DisplayName());
        }
    }
}

确保安装依赖包:Microsoft.EntityFrameworkCore.Relational

【讨论】:

  • 我遇到了这种方法的问题,因为值对象在针对它们设置表名后被视为实体(至少在 EF Core 5 中)。请在下面查看我的答案。
【解决方案4】:

这是@Vicram 答案的扩展。 我在 EF Core 5 中应用了它

modelBuilder.Model.GetEntityTypes()            
    .Configure(e => e.SetTableName(e.DisplayName()));

但是,如果您的域中有值对象,它们都将被视为实体类型并在数据库中创建为表。如果您的值对象都继承自 ValueObject 这样的基本类型,您可以使用以下内容:

modelBuilder.Model.GetEntityTypes()            
    .Where(x => !x.ClrType.IsSubclassOf(typeof(ValueObject)))
    .Configure(e => e.SetTableName(e.DisplayName()));

我没有检查其他 EF 核心版本,但肯定是版本 5 中的情况。

EF Core 5 的另一个缺点是,当您在实体模型中使用继承时,设置表名称会从 Table-per-Hierarchy (TPH) 更改为 Table-per-Type (TPT)

您可以使用以下替代方法(假设您的实体派生自 BaseEntity 类)

modelBuilder.Model.GetEntityTypes()
    .Where(x => x.ClrType.BaseType == typeof(BaseEntity))
    .Configure(e => e.SetTableName(e.DisplayName()));

Configure 扩展名在哪里

public static class ModelBuilderExtensions
{
    public static void Configure(this IEnumerable<IMutableEntityType> entityTypes, Action<IMutableEntityType> convention)
    {
        foreach (var entityType in entityTypes)
        {
            convention(entityType);
        }
    }

    public static void Configure(this IEnumerable<IMutableProperty> propertyTypes, Action<IMutableProperty> convention)
    {
        foreach (var propertyType in propertyTypes)
        {
            convention(propertyType);
        }
    }
}

【讨论】:

  • 最佳答案。
  • 从哪里获得 .Configure 在 EF 6 中?
【解决方案5】:

在 EF Core 2 中,您可以添加 hook。令人费解的是,如果您使用它在具有 asp.net 核心应用程序实体的库项目中生成类,您需要转到包管理器控制台,选择您的库项目作为默认项目,然后在mvc 网络项目。如果你在库中添加钩子,它不会发现钩子。

您可以测试它是否可以使用

public void ConfigureDesignTimeServices(IServiceCollection services)
{
    throw new Exception("works");
    services.AddSingleton<IPluralizer, MyPluralizer>();
}

【讨论】:

    猜你喜欢
    • 2022-01-19
    • 2017-05-08
    • 2022-01-27
    • 2022-02-27
    • 1970-01-01
    • 1970-01-01
    • 2018-08-17
    • 2021-04-17
    • 2021-04-13
    相关资源
    最近更新 更多