无法添加实体类型“X”的种子实体,因为未为所需属性“..ID”提供值

Tom*_*ino 13 c# entity-framework-core entity-framework-core-2.1

我在玩EF Core 2.1 Preview 2。我在使用 HasData (Seed) 方法时遇到了麻烦OnModelCreating(ModelBuilder modelBuilder)

我的模型是没有注释的简单 POCO 类。

public class Tenant {
    public int TenantID {get; set;}
    public string Name {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

在我的DbContext内部OnModelCreating方法中,DB 模型定义为

modelBuilder.Entity<Tenant>(e => {
    e.HasKey(m => m.TenantID)
     .HasName("PK_Tenants");

    e.Property(m => m.TenantID)
     .UseSqlServerIdentityColumn();

    e.Property(m => m.Name)
     .IsRequired()
     .HasMaxLength(256);
}
Run Code Online (Sandbox Code Playgroud)

种子方法定义为:

modelBuilder.Entity<Tenant>().HasData(new []{
   new Tenant {
      TenantID = 0,
      Name = "SystemTenant",
   }
});
Run Code Online (Sandbox Code Playgroud)

在启动期间,当 ctx.Database.Migrate() 运行时,出现异常:无法添加实体类型“租户”的种子实体,因为没有为所需的属性“租户ID”提供值

Tom*_*ino 10

这个例外有点误导。内部必须有某种机制来测试所需的属性,因此它们必须与默认值不同。

我必须做的唯一更改是指定TenantID != 0.

modelBuilder.Entity<Tenant>().HasData(new []{ 
   new Tenant {
      TenantID = 1, // Must be != 0
      Name = "SystemTenant",
   }
});
Run Code Online (Sandbox Code Playgroud)


Tot*_*eRo 6

在对EF Core代码进行逆向工程并找到这行代码后,我创建了一些“hack”来绕过 0 PK 值限制。与@Tomino 的回答相关。这是我截取的扩展代码:

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);
            }          
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在方法中像这样使用它OnModelCreating

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

    //....
}
Run Code Online (Sandbox Code Playgroud)