【问题标题】:How can I add a base table to an existing entity creating TPH model using Entity Framework?如何将基表添加到使用实体框架创建 TPH 模型的现有实体?
【发布时间】:2013-11-20 15:30:08
【问题描述】:

我的数据库中有一个名为 CarDesign 的现有表,它与 Project 具有一对一的关系。我想添加一个名为 Design 的基表以在 TPH 表中使用。所以我可以为像 BoatDesign 这样的东西添加鉴别器。问题是实体框架只想删除旧表并创建一个新表。如何保留我的数据并使用鉴别器来表示当前记录?

我正在使用带有 SQL 的实体框架 5。如果这有助于解决问题,我还将更新到实体框架 6。项目是带有c#的asp.net MVC4

Mapping

public class CarDesignMap : EntityTypeConfiguration<CarDesign>
    {
        public CarDesignMap()
        {
            // Primary Key
            this.HasKey(t => t.Id);

            // Properties
            //this.Property(t => t.Name)
            //.IsRequired();

            this.Property(t => t.RowVersion)
                .IsRequired()
                .IsFixedLength()
                .HasMaxLength(8)
                .IsRowVersion();



            // Relationships
            this.HasMany(t => t.InputVoltages)
                .WithMany(t => t.CarDesign)
                .Map(m =>
                {
                    m.ToTable("InputVoltageCarDesign");
                    m.MapLeftKey("CarDesign_Id");
                    m.MapRightKey("InputVoltage_Id");
                });

            this.HasMany(t => t.LensColors)
                .WithMany(t => t.CarDesign)
                .Map(m =>
                {
                    m.ToTable("LensCarDesign");
                    m.MapLeftKey("CarDesign_Id");
                    m.MapRightKey("LensColor_Id");
                });

            this.HasMany(t => t.LightSourceColors)
                .WithMany(t => t.CarDesign)
                .Map(m =>
                {
                    m.ToTable("LightSourceColorCarDesign");
                    m.MapLeftKey("CarDesign_Id");
                    m.MapRightKey("LightSourceColor_Id");
                });

            this.HasMany(t => t.Standards)
                .WithMany(t => t.CarDesign)
                .Map(m =>
                {
                    m.ToTable("StandardCarDesign");
                    m.MapLeftKey("CarDesign_Id");
                    m.MapRightKey("Standard_Id");
                });

            this.HasOptional(t => t.LightSource)
                .WithMany(t => t.CarDesign)
                .HasForeignKey(d => d.LightSourceId);
        }
    }

型号

public class CarDesign
{
    public CarDesign()
    {
        Approvals = new List<Approval>();
        Standards = new List<Standard>();
        Connectors = new List<Connector>();
        InputVoltages = new List<InputVoltage>();
        LensColors = new List<LensColor>();
        LightSourceColors = new List<LightSourceColor>();
    }


    [Required]
    [Display(Name = "Product Name")]
    public string Name { get; set; }

    public PdsStatus Status { get; set; }

    public Guid SubmittedById { get; set; }
    [Display(Name = "Submitted By")]
    public virtual User SubmittedBy { get; set; }

    public Guid? ApprovedById { get; set; }
    [Display(Name = "Approved By")]
    public virtual User ApprovedBy { get; set; }

    [Display(Name = "Approval Date")]
    [DataType(DataType.Date)]
    public DateTime? ApprovalDate { get; set; }

    [Display(Name = "Submit Date")]
    [DataType(DataType.Date)]
    public DateTime SubmittalDate { get; set; }
    public string SubmittalDateDisplay
    {
        get
        {
            return (SubmittalDate == null) ? "Not Set" : ((DateTime)SubmittalDate).ToString("MM/dd/yy");
        }
    }

    public string Description { get; set; }

    [Display(Name = "Market and Uses")]
    public string MarketAndUses{get;set;}

    [Display(Name = "Target M & L")]
    [DataType(DataType.Currency)]
    public double? TargetPrice { get; set; }



    [Display(Name = "Annual Qty")]
    public int? AnnualQuantities { get; set; }

    [Display(Name = "Current Draw")]
    public double? CurrentDraw { get; set; }



    [Display(Name = "Light Source")]
    public int? LightSourceId { get; set; }
    public virtual LightSource LightSource { get; set; }



    public LengthUnitOfMeasure LengthUnitOfMeasure { get; set; }
    public WeightUnitOfMeasure WeightUnitOfMeasure { get; set; }
    public PhotometricIntensityUnitOfMeasure LightIntensityUnitOfMeasure{ get; set; }

    public virtual ICollection<Approval> Approvals { get; set; }
    public virtual ICollection<Standard> Standards { get; set; }
    public virtual ICollection<Connector> Connectors { get; set; }
    public virtual ICollection<InputVoltage> InputVoltages { get; set; }
    public virtual ICollection<LensColor> LensColors { get; set; }
    public virtual ICollection<LightSourceColor> LightSourceColors { get; set; }
        }
    }

所以我很想拥有

公共课 CarDesign:设计

{

}

【问题讨论】:

  • 你能给我们看一些代码吗?

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


【解决方案1】:

由于您想采用 TPH 继承,EF 将不得不为基类 Design 创建一个表,从而删除您的旧 CarDesign 表。您可以尝试使用迁移来避免丢失数据,但我从未尝试使用现有数据实现 TPH,因此我无法保证迁移将适用于它(恐怕它可能不会)。

至于鉴别器,EF 已经为您处理好了。

这些类看起来像这样:

public abstract class Design
{
    Public int Id { get; set; }
    ...
}

public class CarDesign : Design
{
    ...
}

public class BoatDesign : Design
{
    ...
}

然后,您可以选择为设计创建一个 DbSet,也可以为每个子类型创建一个 DbSet。您在这里的选择:

public DbSet<Design> Designs { get; set; }

或:

public DbSet<CarDesign> CarDesigns { get; set; }
public DbSet<BoatDesign> BoatDesigns { get; set; }

或者您可以拥有所有三个 DbSet。

如果您想查询 Designs DbSet 并让它只返回 CarDesigns,您可以这样做:

var finishedCarDesigns = context.Designs.OfType<CarDesign>().Where(cd => cd.Finished = true);

此外,您可能会发现此链接很有用:http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx

【讨论】:

    【解决方案2】:

    如果你从Foo开始:

    public class Foo
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int BarID { get; set; }
        public virtual Bar Bar { get; set; }
    }
    

    然后添加了一个基类Baz

    public class Foo : Baz
    {
        public string Name { get; set; }
        public int BarID { get; set; }
        public virtual Bar Bar { get; set; }
    }
    
    public class Baz
    {
        public int ID { get; set; }
        public int ApprovedBy { get; set; 
    }
    

    您可以像这样将您的 sql 添加到迁移中:

    public override void Up()
    {
        DropForeignKey("dbo.Foos", "BarID", "dbo.Bars");
        DropIndex("dbo.Foos", new[] { "BarID" });
        CreateTable(
            "dbo.Bazs",
            c => new
                {
                    ID = c.Int(nullable: false, identity: true),
                    ApprovedBy = c.Int(nullable: false),
                    Name = c.String(),
                    BarID = c.Int(),
                    Discriminator = c.String(nullable: false, maxLength: 128),
                })
            .PrimaryKey(t => t.ID)
            .ForeignKey("dbo.Bars", t => t.BarID)
            .Index(t => t.BarID);
    
        //Put your sql here to run before the table is dropped
        Sql(@"INSERT INTO dbo.Bazs (Name, BarID, Discriminator) 
              SELECT Name, BarID, 'Foo' FROM dbo.Foos");
    
        DropTable("dbo.Foos");
    }
    

    如果您有外键要修复,则 sql 会变得更加复杂。我唯一能想到的另一件事是分阶段进行:

    1. 使BoatDesign 继承自CarDesign 并迁移(将向现有表添加一个鉴别器列)

    2. 添加一个新类CarDesign2,它也继承自CarDesign(无需更改数据库)

    3. 将仅适用于CarDesign 的属性移至CarDesign2(无需更改数据库)

    4. 为 CarDesigns 到 Designs 的数据库中的表名称更改编写脚本(Sql Server 将生成一个脚本,该脚本将移动数据以及删除和重新创建)

    5. 在代码中将CarDesign更改为DesignCarDesign2更改为CarDesign

    6. 查看步骤 5 创建的迁移。如果它正在删除并重新创建 CarDesign 表,则将其替换为步骤 4 中生成的 sql,如果不是 woo-hoo!

    7. 让我们知道您的进展情况

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多