Microsoft

EF Core adds DB Seeding back with some gotchas

Looking back down the latest with EF core (in my case 2.1.4), I notice some gotchas when it comes to Data Seeding….

So basically when you involve your migrations with using .HasData it’s understood that you must provide a initial value for all columns that are keys.
  **Side note: this comes from the EF Core team that they want to maintain consistency across multiple migrations. Well, I can understand their reasoning, but I think it’s unnecessary, because we are talking about in most cases initial testing data. I get it.

With this requirement in mind, this brings up some problems with seeding. In particular with data classes that have constructors and entities with private setters. Consider the example (taken from a PluralSight course on this very topic):

public class Location
{
    public int LocationId { get; private set; }
    public string StreetAddress { get; set; }
    public string OpenTime { get; set; }
    public string CloseTime { get; set; }
    public List<Unit> BrewingUnits { get; set; }
    public Location(string streetAddress, string openTime, string closeTime)
    {
        StreetAddress = streetAddress;
        OpenTime = openTime;
        CloseTime = closeTime;
    }
}

For locationId we have a private setter, because this will be handled on the DB as Id type key. Well when it comes to doing a DataSeed:

modelBuilder.Entity<Location>().HasData(
 new Location
  {
        LocationId = 1,
        StreetAddress = "1 Main Street",
        OpenTime = "6AM",
       CloseTime = "4PM"
    });

This code is going to have a problem, because for New Location, the private setter will throw a compiler error, yeap. But EF Core HasData must be able to set ALL key values. Yeah, how to paint oneself into a corner.

Well, anonymous types to the rescue!

modelBuilder.Entity<Location>().HasData(
 new {
      LocationId = 1,
      StreetAddress = "1 Main Street",
      OpenTime = "6AM",
      CloseTime = "4PM"
     });

It becomes anonymous because Location type is removed from the new statement- the Location type is already known because of .Entity of Location type- so EF Core already knows how to build the migration.

If we look at the actual migration code:

migrationBuilder.InsertData(
 table: "Locations",
  columns: new[] { "LocationId", "CloseTime", "OpenTime", "StreetAddress" },
           values: new object[] { 1, "4PM", "6AM", "1 Main Street" });

We see the key is getting set- that will make EF Core happy.

Is this a good or bad way to deal with this? It depends on your take on anonymous types. It does feel a little kluge like. But again, this comes from how the EF Core team decided to handle HasData seeding when it comes to keys. Btw, foreign keys are not excluded from this requirement. 

Leave a Reply