Entity Framework Core seed data with an Identity of 0

Viewed 2784

I'm trying to add some seed data to my model using .HasData in order to populate my database. I use ID 0 within my data model to map to unknown on each table.

When trying to run the application once adding this, I get the following error:

The seed entity for entity type 'DboTable' cannot be added because there was no value provided for the required property 'Id'.

I assumed that EFCore forces a value of null since a integer of 0 is equivalent to null, but when I try to force an integer parse, it still throws the same error.

At this point I'm unsure of how to approach this, any advice would be appreciated.

snippit from DbContext.cs

...
entity.HasData(new DboTable()
{
    Id = 0,               // integer
    Label = "UNKNOWN",    // string
    ...
});
...
2 Answers

I have created little "hack" to bypass 0 PK value restriction after I reverse engineering the EF Core code and I found this line of code.

Here is my snipped extension code:

using System;
using System.Linq;
using System.Collections.Generic;

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace EntityFrameworkCore.CustomMigration
{
    public static class CustomModelBuilder
    {
        public static bool IsSignedInteger(this Type type)
           => type == typeof(int)
              || type == typeof(long)
              || type == typeof(short)
              || type == typeof(sbyte);

        public static void Seed<T>(this ModelBuilder modelBuilder, IEnumerable<T> data) where T : class
        {
            var entnty = modelBuilder.Entity<T>();

            var pk = entnty.Metadata
                .GetProperties()
                .FirstOrDefault(property => 
                    property.RequiresValueGenerator() 
                    && property.IsPrimaryKey()
                    && property.ClrType.IsSignedInteger()
                    && property.ClrType.IsDefaultValue(0)
                );
            if (pk != null)
            {
                entnty.Property(pk.Name).ValueGeneratedNever();
                entnty.HasData(data);
                entnty.Property(pk.Name).UseSqlServerIdentityColumn();
            }
            else
            {
                entnty.HasData(data);
            }          
        }
    }
}

And you can use it like this in OnModelCreating method:

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Seed(new List<Tenant> {
        new Tenant() {TenantID = 0 , Name = string.Empty},
        new Tenant() {TenantID = 1 , Name = "test"}
        //....
        );

    //....
}
Related