简体   繁体   English

更改数据库结构并在Entity Framework中移动数据

[英]Changing structure of database and moving data in Entity Framework

My Database has entities Driver and DriverWork like this: 我的数据库具有如下实体: DriverDriverWork

Edited: 编辑:

public class Driver
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }
}

public class DriverWork
{
    [Key]
    public int Id { get; set; }

    public string FromLocation { get; set; }

    public string ToLocation { get; set; }

    public int Price { get; set; }

    public DateTime Date { get; set; }

    public int DriverId { get; set; }

    [ForeignKey(nameof(DriverId))]
    public Driver Driver { get; set; }
}

And contains many rows in those entities. 并且在那些实体中包含许多行。 Now I've added another Entity with name WorkPage , which changes relation from this: 现在,我添加了另一个名称为WorkPage实体,该实体WorkPage更改了关系:

DriverWork --> Driver

To this: 对此:

DriverWork --> WorkPage --> Driver

Models after the change ( Driver is still the old one): 更改后的型号( Driver仍然是旧版本):

public class Driver
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }
}

public class WorkPage
{
    [Key]
    public int Id { get; set; }

    public byte CommissionPercentage { get; set; }

    public bool IsClosed { get; set; }

    public DateTime? DateClosed { get; set; }

    public int DriverId { get; set; }

    [ForeignKey(nameof(DriverId))]
    public Driver Driver { get; set; }
}

public class DriverWork
{
    [Key]
    public int Id { get; set; }

    public string FromLocation { get; set; }

    public string ToLocation { get; set; }

    public int Price { get; set; }

    public DateTime Date { get; set; }

    public int WorkPageId { get; set; }

    [ForeignKey(nameof(WorkPageId))]
    public WorkPage WorkPage { get; set; }
}

After adding a new migration, I knew that I should make changes in the Up method because some drivers currently don't have any WorkPage s and I should at least add one WorkPage for them, also current DriverWork items must change their DriverId value to a valid WorkPageId that is associated with that Driver . 添加新的迁移后,我知道我应该对Up方法进行更改,因为某些驱动程序当前没有任何WorkPage并且我至少应该WorkPage添加一个WorkPage ,而且当前DriverWork项也必须将其DriverId值更改为与该Driver关联的有效WorkPageId But I don't know how should I do this migration in EF6? 但是我不知道该如何在EF6中进行迁移?

Without making any changes in Up method, EF gives this error after running update-database command: Up方法进行任何更改的情况下,EF在运行update-database命令后给出此错误:

The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.DriverWorks_dbo.WorkPages_WorkPageId". The conflict occurred in database "{dblocation}\KHORSHIDDATA.MDF", table "dbo.WorkPages", column 'Id'.

Any help? 有什么帮助吗?

Sine it's a tough transformation, I would suggest performing it with two passes. 确实,这是一个艰难的转变,我建议进行两次通过。

First, keep the DriverId FK in the DriverWork and make DriverId in WorkPage optional (nullable): 首先,将DriverId FK保留在DriverWork ,并将DriverId中的WorkPage可选(可空):

public class WorkPage
{
    [Key]
    public int Id { get; set; }

    public byte CommissionPercentage { get; set; }

    public bool IsClosed { get; set; }

    public DateTime? DateClosed { get; set; }

    public int? DriverId { get; set; }

    [ForeignKey(nameof(DriverId))]
    public Driver Driver { get; set; }
}

public class DriverWork
{
    [Key]
    public int Id { get; set; }

    public string FromLocation { get; set; }

    public string ToLocation { get; set; }

    public int Price { get; set; }

    public DateTime Date { get; set; }

    public int DriverId { get; set; }

    [ForeignKey(nameof(DriverId))]
    public Driver Driver { get; set; }

    public int WorkPageId { get; set; }

    [ForeignKey(nameof(WorkPageId))]
    public WorkPage WorkPage { get; set; }
}

Generate new migration. 产生新的迁移。 It should be something like this: 应该是这样的:

public override void Up()
{
    CreateTable(
        "dbo.WorkPage",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                CommissionPercentage = c.Byte(nullable: false),
                IsClosed = c.Boolean(nullable: false),
                DateClosed = c.DateTime(),
                DriverId = c.Int(nullable: false),
            })
        .PrimaryKey(t => t.Id)
        .ForeignKey("dbo.Driver", t => t.DriverId, cascadeDelete: true)
        .Index(t => t.DriverId);

    AddColumn("dbo.DriverWork", "WorkPageId", c => c.Int());
    CreateIndex("dbo.DriverWork", "WorkPageId");
    AddForeignKey("dbo.DriverWork", "WorkPageId", "dbo.WorkPage", "Id");
}

Execute the migration. 执行迁移。 Then restore the desired entity model by removing the Driver from DriverWork and making DriverId in WorkPage required (non null): 然后通过从DriverWork删除Driver并在DriverId中设置WorkPage必需(非null)来恢复所需的实体模型:

public class WorkPage
{
    [Key]
    public int Id { get; set; }

    public byte CommissionPercentage { get; set; }

    public bool IsClosed { get; set; }

    public DateTime? DateClosed { get; set; }

    public int DriverId { get; set; }

    [ForeignKey(nameof(DriverId))]
    public Driver Driver { get; set; }
}

public class DriverWork
{
    [Key]
    public int Id { get; set; }

    public string FromLocation { get; set; }

    public string ToLocation { get; set; }

    public int Price { get; set; }

    public DateTime Date { get; set; }

    public int WorkPageId { get; set; }

    [ForeignKey(nameof(WorkPageId))]
    public WorkPage WorkPage { get; set; }
}

Generate a second new migration. 生成第二个新迁移。 It should look something like this: 它看起来应该像这样:

public override void Up()
{
    DropForeignKey("dbo.DriverWork", "DriverId", "dbo.Driver");
    DropForeignKey("dbo.DriverWork", "WorkPageId", "dbo.WorkPages");
    DropIndex("dbo.DriverWork", new[] { "DriverId" });
    DropIndex("dbo.DriverWork", new[] { "WorkPageId" });
    AlterColumn("dbo.DriverWork", "WorkPageId", c => c.Int(nullable: false));
    CreateIndex("dbo.DriverWork", "WorkPageId");
    AddForeignKey("dbo.DriverWork", "WorkPageId", "dbo.WorkPage", "Id", cascadeDelete: true);
    DropColumn("dbo.DriverWork", "DriverId");
}

Use Sql methods to populate the WorkPage table data and update the WorkTableId FK before making it required. 使用Sql方法填充WorkPage表数据并在需要之前更新WorkTableId FK。 For instance, insert the following at the beginning of the Up method: 例如,在Up方法的开头插入以下内容:

Sql(@"insert into dbo.WorkPage (CommissionPercentage, IsClosed, DateClosed, DriverId) select 0, 0, null, DriverId from dbo.DriverWork");
Sql(@"update dbo.DriverWork set WorkPageId = WP.Id from dbo.DriverWork DW join dbo.WorkPage WP on DW.DriverId = WP.DriverId");

Execute the migration and you are done. 执行迁移,您就完成了。

Actually the Sql calls which transform the data can be at the end of the first migration Up method. 实际上,转换数据的Sql调用可以在第一个Migration Up方法的结尾。

Knowing all that in advance, you can keep your new model as is (skip the first step) and simply replace the generated migration Up method with the union of the above two, eg 事先了解所有这些信息,您可以保持新模型不变(跳过第一步),并用上述两个方法的并集简单地替换生成的migration Up方法,例如

public override void Up()
{
    CreateTable(
        "dbo.WorkPage",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                CommissionPercentage = c.Byte(nullable: false),
                IsClosed = c.Boolean(nullable: false),
                DateClosed = c.DateTime(),
                DriverId = c.Int(nullable: false),
            })
        .PrimaryKey(t => t.Id)
        .ForeignKey("dbo.Driver", t => t.DriverId, cascadeDelete: true)
        .Index(t => t.DriverId);

    AddColumn("dbo.DriverWork", "WorkPageId", c => c.Int());
    CreateIndex("dbo.DriverWork", "WorkPageId");
    AddForeignKey("dbo.DriverWork", "WorkPageId", "dbo.WorkPage", "Id");

    Sql(@"insert into dbo.WorkPage (CommissionPercentage, IsClosed, DateClosed, DriverId) select 0, 0, null, DriverId from dbo.DriverWork");
    Sql(@"update dbo.DriverWork set WorkPageId = WP.Id from dbo.DriverWork DW join dbo.WorkPage WP on DW.DriverId = WP.DriverId");

    DropForeignKey("dbo.DriverWork", "DriverId", "dbo.Driver");
    DropForeignKey("dbo.DriverWork", "WorkPageId", "dbo.WorkPages");
    DropIndex("dbo.DriverWork", new[] { "DriverId" });
    DropIndex("dbo.DriverWork", new[] { "WorkPageId" });
    AlterColumn("dbo.DriverWork", "WorkPageId", c => c.Int(nullable: false));
    CreateIndex("dbo.DriverWork", "WorkPageId");
    AddForeignKey("dbo.DriverWork", "WorkPageId", "dbo.WorkPage", "Id", cascadeDelete: true);
    DropColumn("dbo.DriverWork", "DriverId");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM