Entity Framework Core 2.0:如何配置抽象基类一次

23

我有一个基础模型:

public abstract class Status
{
     public string updateUserName { get; set; }
}

然后是一个扩展了上述基本模型的模型:

public class Item : Status
{
     public int Id { get; set; }
     public string Description { get; set; }
}

然后我为每个定义了配置类:

public class ItemConfiguration : IEntityTypeConfiguration<Item>
{
    public void Configure(EntityTypeBuilder<Item> builder)
    {
        builder.ToTable("Item", "dbo").HasKey(c => c.Id);
        builder.Property(c => c.Description).IsRequired().HasMaxLength(100);
    }
}

public class StatusConfiguration : IEntityTypeConfiguration<Status>
{
    public void Configure(EntityTypeBuilder<Status> builder)
    {
        builder.Property(c => c.updateUserName).IsRequired().HasMaxLength(50);
    }

现在,我有以下的Context类:

public class TestDbContext : DbContext
{
    public TestDbContext(DbContextOptions<TestDbContext> options) : base(options)
    {
    }

    public DbSet<Item> Item { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new ItemConfiguration());
    }
}

我正在尝试弄清如何将在StatusConfiguration类中定义的状态模型配置应用于所有扩展它的模型(在本例中仅有一个:Item)。我希望避免每次使用时都重新定义相同的状态模型配置。该状态模型实质上是与每个Item记录相关联的元数据(即数据库中的一个Item表,包含两个模型中定义的所有属性;没有更多,也没有更少)。

例如,我的当前实现是以下ItemConfiguration类,而不使用StatusConfiguration类:

public class ItemConfiguration : IEntityTypeConfiguration<Item>
{
    public void Configure(EntityTypeBuilder<Item> builder)
    {
        builder.ToTable("Item", "dbo").HasKey(c => c.Id);
        builder.Property(c => c.Description).IsRequired().HasMaxLength(100);
        builder.Property(c => c.updateUserName).IsRequired().HasMaxLength(50);
    }
}

当前的实现方式可以正常工作并按预期迁移到数据库中,但我希望今后能够找到一种更易于管理的方式。

我假设我可以扩展ItemConfiguration类以包括StatusConfiguration类,但是在网上找不到该方法的示例。我希望有更多经验的人能够指点一下?

如果需要额外的信息,请告诉我。

2个回答

57
如果我理解正确,Status只是一个基类而不是参与数据库继承的基础实体。在这种情况下,重要的是永远不要直接在实体模型和配置中引用Status类,即没有DbSet<Status>、没有类型为StatusICollection<Status>的导航属性,没有modelBuilder.Entity<Status>()调用和没有IEntityTypeConfiguration<Status>。相反,您始终必须引用从Status继承的具体类型。为了重用配置代码,应使用受限制的泛型方法或类,并传递具体实体类型。由于您正在使用IEntityTypeConfiguration类,因此最自然的可能是使您的StatusConfiguration类成为泛型:
public class StatusConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
    where TEntity : Status
{
    public virtual void Configure(EntityTypeBuilder<TEntity> builder)
    {
        builder.Property(c => c.updateUserName).IsRequired().HasMaxLength(50);
    }
}

让派生实体配置类从中继承:

public class ItemConfiguration : StatusConfiguration<Item>
{
    public override void Configure(EntityTypeBuilder<Item> builder)
    {
        base.Configure(builder); // <--
        builder.ToTable("Item", "dbo").HasKey(c => c.Id);
        builder.Property(c => c.Description).IsRequired().HasMaxLength(100);
    }
}

1
你说得对极了。我确实在寻找如何实现那个受限制的泛型方法并传递具体的实体类型。非常感谢你的时间! - TheDirtyJenks
1
@Ivan,如果不利用 IEntityTypeConfiguration<TEntity> ,我该如何实现这个功能?https://dev59.com/oVQJ5IYBdhLWcg3wtYLq - ibubi
1
@ibubi 我已经在那里发布了答案。 - Ivan Stoev
1
谢谢您!我一直在尝试但无法使其工作。最初我错过了"base.Configure..."的输入,添加后一切都完美运行。 - user1489765
1
非常好的答案 - 这对我帮助很大。谢谢! - Ed Graham
显示剩余7条评论

0
你可以在 OnModelCreating 方法中使用反射,并为基类使用通用的 Configuration 类来完成此操作,而无需为每个实体调用 base.Configure(builder)。
public class StatusConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
    where TEntity : Status
{
    public virtual void Configure(EntityTypeBuilder<TEntity> builder)
    {
        builder.Property(c => c.updateUserName).IsRequired().HasMaxLength(50);
    }
}

在OnModel创建中,找到继承基类的类,并像下面这样创建配置的实例:
      var subTypes= Assembly
           .GetAssembly(typeof(Status))
           .GetTypes()
           .Where(c => c.IsSubclassOf(typeof(Status)));
        foreach (var item in subTypes)
        {
            Type baseEntityConfigGenericType= typeof(StatusConfiguration<>);
            Type[] typeArgs = { item };
            Type constructed = baseEntityConfigGenericType.MakeGenericType(typeArgs);
            dynamic o = Activator.CreateInstance(constructed);
            if (builder.Model.FindEntityType(item) != null)
                builder.ApplyConfiguration(o);
}

现在每次您添加新的子类型时,在迁移过程中,它将自动考虑基本类型的规格。

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