如何在IDesignTimeServices中正确使用IPluralizer

Wue*_*ueF 2 c# entity-framework-core asp.net-core

在我的应用程序中,我使用代码优先方法,并且仅通过将实体添加到DbContext中IEntityTypeConfiguration<>。我的目标是实现多元化的表名,即Models for Model

在阅读了文档文章之后, 我的疑问是我的复数器应该被注册并IPluralizer在创建迁移时使用,但是不是。

当然,我可以隐式使用DbSet<Model> Models {get;set;}或use builder.ToTable("Models");,但是在我的通用方案中,我想避免这种情况,尤其是因为我希望某些模型不要覆盖抽象的通用方案。

问题是,我是在做错什么,还是我误解了它的行为方式

AppDesignService.cs

public class AppDesignService : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
    {
        Debugger.Launch();
        services.AddSingleton<IPluralizer, InflectorPluralizer>();
    }
}
Run Code Online (Sandbox Code Playgroud)

MyDbContext.cs

public class AppDbContext : IdentityDbContext<AppUser,AppRole,Guid>
{
    public EmsDbContext(DbContextOptions options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.ApplyConfigurationsFromAssembly(Assembly.GetAssembly(typeof(AppDbContext)));
    }
}
Run Code Online (Sandbox Code Playgroud)

启动文件

public void ConfigureServices(IServiceCollection services)
{
    var connectionString = Configuration.GetConnectionString("DefaultConnection");

    services.AddDbContext<DbContext, AppDbContext>(opt =>
     {
         opt.UseSqlServer(connectionString, sqlOpt =>
         {
             sqlOpt.EnableRetryOnFailure(3);
         });
     });

     // code skipped for brevity
}
Run Code Online (Sandbox Code Playgroud)

设定档

public interface IEntity
{
    int Id {get;set;}
}

public class Model : IEntity
{
    public int Id {get;set;}
    public string Name {get;set;}
}



public abstract class DbEntityConfig<T> : IEntityTypeConfiguration<T>
    where T : class, IEntity
{
    public void Configure(EntityTypeBuilder<T> builder)
    {
        builder.HasKey(m => m.Id);
    }
}


public class ModelEntityConfig : DbEntityConfig<Model>
{
    public void Configure(EntityTypeBuilder<Model> builder)
    {
        base.Configure(builder);

        // Of course I want to avoid this call, cos TheOtherModel might not override base method
        // builder.ToTable("Models");

        builder.Property(m => m.Name).HasMaxLength(25);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果

public partial class Test : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Model",
            columns: table => new

            // code skipped for brevity
    }
}
Run Code Online (Sandbox Code Playgroud)

预期结果:

public partial class Test : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Models",
            columns: table => new

            // code skipped for brevity
    }
}
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 5

链接的文章不正确。从DbContext Scaffolding EF Core文档的复数挂钩中可以看到:

EF Core 2.0引入了一项新IPluralizer服务,该服务用于单数实体类型名称和复数DbSet名称。

不久,它仅由脚手架命令使用,因此不能用于更改表名称模型约定

通常,迁移工具使用该模型的方式通过约定,数据注释和流利的API进行配置。因此,应用自定义约定应与模型API一起使用OnModelCreating。像这样:

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    entityType.Relational().TableName = GetTableName(entityType);
Run Code Online (Sandbox Code Playgroud)

where GetTableName方法实现您的命名约定:

string GetTableName(IEntityType entityType)
{
    // use entiityType.Name and other info
    return ...; 
} 
Run Code Online (Sandbox Code Playgroud)

更新(EF核心3.0+):使用entityType.SetTableName(...)代替entityType.Relational().TableName = ...