【问题标题】:Entity Framework Migration Inheritance without creating the parent table实体框架迁移继承而不创建父表
【发布时间】:2019-01-08 01:40:13
【问题描述】:

我的数据库对象都继承自具有一些基本属性的父类。

基础实体

public abstract class Entity : IAuditable
{
    public int Id { get; set; }
    public string CreatedBy { get; set; }
    public int? CreatedDate { get; set; }
    public string UpdateBy { get; set; }
    public int? UpdatedDate { get; set; }
}

基础实体配置文件

public EntityConfiguration()
{
    HasKey(e => e.Id);

    Property(e => e.Id)
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    Property(e => e.CreatedBy)
        .IsUnicode(false)
        .HasMaxLength(255);

    Property(e => e.UpdatedBy)
        .IsUnicode(false)
        .HasMaxLength(255);
}

我在所有子类上子类化实体以继承公共属性

public class User : Entity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

DbContext

public class SomeContext : DbContext
{
    public SomeContext() : base("name=DefaultConnection")
    {
    }

    public static SomeContext Create()
    {
        return new SomeContext();
    }

    public DbSet<Collaboration> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new EntityConfiguration());
        modelBuilder.Configurations.Add(new UserConfiguration());
    }
}

当我创建迁移时,它将正确创建所有继承的属性,但即使我没有 DbSet,它仍会创建父类(实体)。如果我删除在 OnModelCreating 方法中添加配置设置的行,我不会获得最大长度和 Unicode 设置。

有没有一种方法可以在不实际创建父表且不将配置添加到所有子类配置文件的情况下使用配置属性。

【问题讨论】:

    标签: c# sql-server entity-framework-6


    【解决方案1】:

    首先删除您的 Base EntityConfiguration 类,因为您不想为它生成数据库表

    解决方案 1:使用数据注释

    你的Base Entity 类应该如下:

    public abstract class Entity
    {
            [Key]
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public int Id { get; set; }
    
            [MaxLength(255)]
            [Column(TypeName = "Varchar")]
            public string CreatedBy { get; set; }
    
            public DateTime? CreatedDate { get; set; }
    
            [MaxLength(255)]
            [Column(TypeName = "Varchar")]
            public string UpdateBy { get; set; }
    
            public DateTime? UpdatedDate { get; set; }
     }
    

    然后你的DbContext 应该如下:

    public class SomeContext : DbContext
    {
        public SomeContext() : base("name=DefaultConnection")
        {
        }
    
        public static SomeContext Create()
        {
            return new SomeContext();
        }
    
        public DbSet<User> Users { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new UserConfiguration());
        }
    
    }
    

    解决方案 2:使用 Fluent API

    DbContext 中的 Base Entity 配置应如下所示:

    public class SomeContext : DbContext
    {
        public SomeContext() : base("name=DefaultConnection")
        {
        }
    
        public static SomeContext Create()
        {
            return new SomeContext();
        }
    
        public DbSet<Collaboration> Users { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
           modelBuilder.Types<Entity>().Configure(c =>
            {
                c.HasKey(e => e.Id);
    
                c.Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
                c.Property(e => e.CreatedBy)
                    .IsUnicode(false)
                    .HasMaxLength(255);
    
                c.Property(e => e.UpdateBy)
                    .IsUnicode(false)
                    .HasMaxLength(255);
            });
            modelBuilder.Configurations.Add(new UserConfiguration());
        }
    }
    

    在这两种情况下,Migration 都会生成Users 表,如下所示:

    public override void Up()
    {
                CreateTable(
                    "dbo.Users",
                    c => new
                        {
                            Id = c.Int(nullable: false, identity: true),
                            FirstName = c.String(),
                            LastName = c.String(),
                            CreatedBy = c.String(maxLength: 255, unicode: false),
                            CreatedDate = c.DateTime(),
                            UpdateBy = c.String(maxLength: 255, unicode: false),
                            UpdatedDate = c.DateTime(),
                        })
                    .PrimaryKey(t => t.Id);
    
      }
    

    希望您的问题能得到解决!

    【讨论】:

    • 我之前确实试过这个。虽然它会给我继承的字段,但我丢失了 EntityTypeConfiguration 类中的自定义字段属性,例如最大长度和 Unicode。我确实提出了一个解决方案,我会在两天的宽限期结束时发布该解决方案
    • @Dblock247 为什么会丢失自定义字段属性?好的,让我再检查一次。
    • 因为您要从 OnModelConfiguration 中删除 modelBuilder.Configurations.Add(new EntityConfiguration())。该类包含所有配置信息。此外,重点不是为每个子实体添加配置。我希望它继承父级的所有内容
    • 但我正在使用UserCofiguration..请仔细阅读我的答案..没问题我正在用一个新项目检查它。
    • 是的,我知道,但如果我打算这样做的话。我不需要继承。我必须将其添加到每个子实体配置中
    【解决方案2】:

    如果有人对这里感兴趣,我想出了两个解决方案。我选择了第二个,因为它似乎是更准确的解决方案。

    解决方案 1

    对基类使用Types配置,任何继承基类的东西也会继承配置。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Types<Entity>().Configure(c =>
        {
            c.HasKey(e => e.Id);
    
            c.Property(e => e.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
            c.Property(e => e.CreatedBy)
                .IsUnicode(false)
                .HasMaxLength(255);
    
            c.Property(e => e.UpdatedBy)
                .IsUnicode(false)
                .HasMaxLength(255);
        });
    
        modelBuilder.Configurations.Add(new UserConfiguration());
    } 
    

    解决方案 2

    使用泛型、接口和继承的组合来创建基础 EntityTypeConfiguration 类。然后让其他实体类型配置类从它继承。

    public interface IEntity
    {
        int Id { get; set; }
    }
    
    public interface IAuditable
    {
        string CreatedBy { get; set; }
        DateTime? CreatedDate { get; set; }
        string UpdatedBy { get; set; }
        DateTime? UpdatedDate { get; set; }
    }
    
    public class EntityConfiguration<T> : EntityTypeConfiguration<T> where T : class, IEntity, IAuditable
    {
        public EntityConfiguration()
        {
            HasKey(e => e.Id);
    
            Property(e => e.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
            Property(e => e.CreatedBy)
                .IsUnicode(false)
                .HasMaxLength(255);
    
            Property(e => e.UpdatedBy)
                .IsUnicode(false)
                .HasMaxLength(255);
        }
    }
    

    【讨论】:

      【解决方案3】:

      这种首先使用 EF 代码的继承方法是 Table per Concrete Type TPC Hierarchy

      在链接中,您可以找到所有逻辑以及如何实现它的示例。我知道我不应该提供链接,但请检查链接,它拥有一切:)

      示例、代码说明、图表和图像。我认为这正是您了解 TPC 所需要的。

      【讨论】:

      • 我确实遇到了这个链接,但它不是我如何在 EntityConfiguration 类中进行更改的方式。我最终使用 modelBuilder.Types().Configure(c => {}) 来解决我的问题。两天的宽限期结束后,我会尽快发布答案。
      猜你喜欢
      • 1970-01-01
      • 2016-03-26
      • 2013-04-21
      • 1970-01-01
      • 1970-01-01
      • 2011-05-19
      • 2010-10-07
      • 1970-01-01
      相关资源
      最近更新 更多