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

时间:2018-04-24 20:57:15

标签: c# entity-framework-core entity-framework-core-2.1

我正在玩智慧 EF Core 2.1 Preview 2 。 我在OnModelCreating(ModelBuilder modelBuilder)

中遇到了HasData(种子)方法的麻烦

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

public class Tenant {
    public int TenantID {get; set;}
    public string Name {get; set;}
}
我的DbContextOnModelCreating方法中的

是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);
}

并且种子方法定义为:

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

在startap期间,当运行ctx.Database.Migrate()时,我得到了异常: 无法添加实体类型“租户”的种子实体,因为没有为所需属性'TenantID

提供值

4 个答案:

答案 0 :(得分:3)

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

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

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

答案 1 :(得分:2)

在对EF Core代码进行反向工程并发现了this行代码之后,我创建了一些小的“ 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);
            }          
        }
    }
}

您可以在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"}
        //....
        );

    //....
}

答案 2 :(得分:0)

我正在使用自定义服务将数据提取到数据库,我这样做是这样的:

C:\Program Files\JetBrains\IntelliJ IDEA xxxx.xx.xx\bin

我必须将其更改为private void _MakeMesh(int sides, float radius = 0.5f) { m_LiquidMesh.Clear(); float angleStep = 360.0f / (float) sides; List<Vector3> vertexes = new List<Vector3>(); List<int> triangles = new List<int>(); List<Vector2> uvs = new List<Vector2>(); Quaternion rotation = Quaternion.Euler(0.0f, angleStep, 0.0f); // Make first triangle. vertexes.Add(new Vector3(0.0f, 0.0f, 0.0f)); vertexes.Add(new Vector3(radius, 0.0f, 0.0f)); vertexes.Add(rotation * vertexes[1]); // First UV ?? uvs.Add(new Vector2(0, 0)); uvs.Add(new Vector2(1, 0)); uvs.Add(rotation * uvs[1]); // Add triangle indices. triangles.Add(0); triangles.Add(1); triangles.Add(2); for (int i = 0; i < sides - 1; i++) { triangles.Add(0); triangles.Add(vertexes.Count - 1); triangles.Add(vertexes.Count); // UV ?? vertexes.Add(rotation * vertexes[vertexes.Count - 1]); } m_LiquidMesh.vertices = vertexes.ToArray(); m_LiquidMesh.triangles = triangles.ToArray(); m_LiquidMesh.uv = uvs.ToArray(); m_LiquidMesh.RecalculateNormals(); m_LiquidMesh.RecalculateBounds(); Debug.Log("<color=yellow>Liquid mesh created</color>"); } How does mapping UV work in a case like this?

builder.Entity<EntityName>().HasData(someSerive.GetById(id).AsEnumerable());

答案 3 :(得分:0)

我在我的一个存储库中收到此错误。

Exception has occurred: CLR/System.InvalidOperationException
Exception thrown: 'System.InvalidOperationException' in Microsoft.EntityFrameworkCore.dll: 
'The seed entity for entity type 'SubscriptionType'
cannot be added because a default value was provided for the required property 'Id'. 

Please provide a value different from '00000000-0000-0000-0000-000000000000'.'
       at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateData(IModel model, IDiagnosticsLogger`1 logger)
       at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
       at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
       at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)

问题是我使用 new Guid() 将值分配给 id 字段,这只是一个错误。 new Guid 将只创建全零的虚拟 Guid,而 Guid.NewGuid() 将创建唯一的 Guid。所以,我不得不在我的代码中使用 Guid.NewGuid()

builder.Entity<SubscriptionType>(b =>
            {
                b.HasKey(k => k.Id);
                b.HasData(new SubscriptionType { Id = Guid.NewGuid(), Name = "SeatBased" },
                               new SubscriptionType { Id = Guid.NewGuid(), Name = "NonSeatBased" },
                               new SubscriptionType { Id = Guid.NewGuid(), Name = "AzureEntitlement" },
                               new SubscriptionType { Id = Guid.NewGuid(), Name = "Bundle" });
            });