如何使用Entity Framework将基表添加到创建TPH模型的现有实体?

时间:2013-11-20 15:30:08

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

我的数据库中有一个名为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:设计

{

}

2 个答案:

答案 0 :(得分:0)

由于您希望采用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。

如果你想要查询设计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

答案 1 :(得分:0)

如果您从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 to Designs的数据库中编写表名更改(Sql Server将生成一个脚本,该脚本将移动数据以及删除并重新创建)

  5. 在代码更改CarDesignDesignCarDesign2CarDesign

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

  7. 告诉我们您的情况