Изменение структуры базы данных и перемещение данных в Entity Framework - PullRequest
0 голосов
/ 28 августа 2018

В моей базе данных есть объекты Driver и DriverWork, например:

Отредактировано:

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; }
}

И содержит много строк в этих сущностях. Теперь я добавил еще одну сущность с именем WorkPage, которая меняет отношение с этого:

DriverWork --> Driver

К этому:

DriverWork --> WorkPage --> Driver

Модели после изменения (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; }
}

После добавления новой миграции я знал, что должен внести изменения в метод Up, потому что некоторые драйверы в настоящее время не имеют WorkPage s, и я должен хотя бы добавить один WorkPage для них, также текущий Элементы DriverWork должны изменить свое значение DriverId на действительное значение WorkPageId, связанное с этим Driver. Но я не знаю, как мне выполнить эту миграцию в EF6?

Не внося никаких изменений в метод 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'.

Любая помощь?

1 Ответ

0 голосов
/ 28 августа 2018

Так как это сложное преобразование, я бы предложил выполнить его за два прохода.

Во-первых, оставьте 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; }
}

Создание новой миграции. Это должно быть что-то вроде этого:

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");
}

Выполнить миграцию. Затем восстановите желаемую модель сущности, удалив Driver из 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 WorkPageId { get; set; }

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

Создайте вторую новую миграцию. Это должно выглядеть примерно так:

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");
}

Используйте методы Sql, чтобы заполнить данные таблицы WorkPage и обновить WorkTableId FK, прежде чем сделать это необходимым. Например, введите в начале метода 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");

Выполните миграцию, и все готово.

На самом деле вызовы Sql, которые преобразуют данные, могут выполняться в конце первого метода миграции Up.

Зная все это заранее, вы можете сохранить новую модель как есть (пропустите первый шаг) и просто заменить сгенерированный метод миграции 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");
}
...