Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Core seed data with an Identity of 0

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
    ...
});
...
like image 836
expenguin Avatar asked Oct 15 '25 02:10

expenguin


2 Answers

Turns out that EF Core 2.1 doesn't support a PK value of 0.

Unfortunately, any seed data trying to use a value of 0 for a PK will have to run a migration with custom SQL to insert their PK 0 records.

see: https://github.com/aspnet/EntityFrameworkCore/issues/12399

like image 51
expenguin Avatar answered Oct 17 '25 16:10

expenguin


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

    //....
}
like image 31
TotPeRo Avatar answered Oct 17 '25 15:10

TotPeRo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!