Entity framework core, code first migration with d

2019-06-27 20:34发布

问题:

I am trying to use EF Core code first migrations to de-normalise an existing table.

I have en existing table LoginEvent which data looks like this:

╔═════════════════════════════════════════════════╗
║                   LoginEvent                    ║
╠════╦══════════╦═══════════╦════════════╦════════╣
║ Id ║ VenueRef ║ VenueName ║ OccurredAt ║ UserId ║
╠════╬══════════╬═══════════╬════════════╬════════╣
║ 1  ║ ven01    ║ Venue 1   ║ 2018-01-29 ║ 5      ║
╠════╬══════════╬═══════════╬════════════╬════════╣
║ 2  ║ ven02    ║ Venue 2   ║ 2018-01-30 ║ 7      ║
╠════╬══════════╬═══════════╬════════════╬════════╣
║ 3  ║ ven01    ║ Venue 1   ║ 2018-02-01 ║ 9      ║
╚════╩══════════╩═══════════╩════════════╩════════╝
public class LoginEvent
{
    [Key]
    public int Id { get; set; }
    public string VenueRef { get; set; }
    public string VenueName { get; set; }
    public DateTime OccurredAt { get; set; }
    public User User { get; set; }
}

And I want to normalise this into two tables: LoginEvent and Venue, like so:

╔═════════════════════════════════════╗
║             LoginEvent              ║
╠════╦══════════╦════════════╦════════╣
║ Id ║ VenueRef ║ OccurredAt ║ UserId ║
╠════╬══════════╬════════════╬════════╣
║ 1  ║ ven01    ║ 2018-01-29 ║ 5      ║
╠════╬══════════╬════════════╬════════╣
║ 2  ║ ven02    ║ 2018-01-30 ║ 7      ║
╠════╬══════════╬════════════╬════════╣
║ 3  ║ ven01    ║ 2018-02-01 ║ 9      ║
╚════╩══════════╩════════════╩════════╝
╔══════════════════════╗
║        Venue         ║
╠══════════╦═══════════╣
║ VenueRef ║ VenueName ║
╠══════════╬═══════════╣
║ ven01    ║ Venue 1   ║
╠══════════╬═══════════╣
║ ven02    ║ Venue 2   ║
╚══════════╩═══════════╝

Now, I have done this by adding a new Venue domain object and having the LoginEvent reference it, like so:

public class LoginEvent
{
    [Key]
    public int Id { get; set; }    
    public string VenueRef { get; set; }
    public DateTime OccurredAt { get; set; }
    public Venue Venue { get; set; }
    public User User { get; set; }
}
public class Venue
{
    [Key]
    public string VenueRef { get; set; }
    public string VenueName { get; set; }
}

I've then created a migration, which (correctly):

  1. Creates the new Venue table
  2. Drops the VenueName column
  3. Sets up the foreign key constraint between the two

However, what I need to be able to do is run a data migration between steps 1 and 2 so that the existing Venues are in the new table before dropping the column and before setting up the constraint (otherwise, I'll lose data and the constraint fails as I don't have associated Venues).

I'd like to run something like this as my data migration:

INSERT INTO Venue SELECT DISTINCT VenueRef, VenueName FROM LoginEvent

How should I do this?

回答1:

You can execute any SQL using migrationBuilder.Sql(theSqlString).

In your case

migrationBuilder.Sql("INSERT INTO Venue SELECT DISTINCT VenueRef, VenueName FROM LoginEvent");

Run this in the migration after creating the new table Venue and before dropping the old column VenueName.

See also Custom Migrations Operations.