【问题标题】:Add-Migration with seeds throwing "no value provided" exception带有种子的添加迁移引发“未提供值”异常
【发布时间】:2019-05-20 19:21:04
【问题描述】:

我正在尝试创建一个包,该包将帮助使用 JSON 文件中的数据为数据库播种,这些文件可以手动创建或从旧数据库中提取。目前,我创建了一个通用类SeedCreator<T>,它从给定文件(实体名称加上.json)中检索JSON,并将其反序列化为给定类型的对象。这部分工作正常。

为了使这个过程尽可能动态化,我通过使用命名空间Entities 识别所有类来对项目中的实体使用反射。有了这个,我遍历检索到的List 并检查 JSON 文件是否存在。如果是,我将路径和泛型类型传递给SeedsCreator 类。在运行Add-Migration 时进行调试时,数据会按照我对 JSON 文件的预期返回,但在变量modelBuilder 返回后,我收到错误The seed entity for entity type 'Table1' cannot be added because there was no value provided for the required property 'Id'.

如果我手动输入以下内容,它就可以正常工作。

modelBuilder.Entity(typeof(Table1)).HasData(data);

任何帮助将不胜感激。特别是如果我是盲人并且做了一些非常简单和愚蠢的事情。

public class Seeds
{
    public ModelBuilder CreateSeeds(ModelBuilder modelBuilder)
    {
        var entities = (from t in Assembly.GetExecutingAssembly().GetTypes()
                       where t.Namespace != null && (t.IsClass && t.Namespace.Contains("Entities"))
                       select t).ToList();

        foreach (var type in entities)
        {
            if (File.Exists("./Seeds/" + type.Name + ".json"))
            {
                Type[] typeArr = { type };
                var seeds = typeof(SeedCreator<>).MakeGenericType(typeArr);
                var activatedSeeds = Activator.CreateInstance(seeds);
                var data = seeds.GetMethod("GetSeeds")?.Invoke(activatedSeeds, new object[] { "./Seeds/" + type.Name + ".json" });
                modelBuilder.Entity(type).HasData(data);
            }
        }

        return modelBuilder;
    }
}

public class SeedCreator<T>
{
    public List<T> GetSeeds(string jsonPath)
    {
        using (var sr = new StreamReader(jsonPath))
            return JsonConvert.DeserializeObject<List<T>>(sr.ReadToEnd());
    }
}

public class Table1
{
    public int Id { get; set; }
}

在 DbContext 内部

using (var dataSeed = new Seeds()) modelBuilder = dataSeed.CreateSeeds(modelBuilder);

示例 JSON 文件 (Table1.json)

[
  {
    "id": 1
  },
  {
    "id": 2
  }
]

堆栈跟踪

System.InvalidOperationException: The seed entity for entity type 'Table1' cannot be added because there was no value provided for the required property 'Id'. at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateData(IModel model) at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model) at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model) at Microsoft.EntityFrameworkCore.Internal.SqlServerModelValidator.Validate(IModel model) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ValidatingConvention.Apply(InternalModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelBuilt(InternalModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel() at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy`1.CreateValue() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure`1 accessor) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType) at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

【问题讨论】:

  • 你的 JSON 文件(或者至少你在这里写的)有id,而你的模型有Id。就这么简单吗?
  • JsonConvert 将 camelCase 反序列化为类。我将在一秒钟内更新问题以显示有效的方法
  • @Pierre-LoupPagnez 只是尝试确认它并没有改变任何东西。我希望事情没有那么简单。

标签: c# .net-core entity-framework-core asp.net-core-2.1 ef-core-2.1


【解决方案1】:

你正陷入典型的params object[] 陷阱。

HasData 方法有 2 个重载 - 一个带有 params object[] data,另一个带有 IEnumerable&lt;object&gt; data。由于反射调用,您的data 变量的类型是object。因此,您使用 singleobject[] 调用第一个重载,其中包含您的 data

如果您想知道为什么异常消息告诉您没有为属性提供值,那么解释很简单。 HasData 不要求传递的对象与被播种的实体类型相同。这是为了允许指定实体类中不存在但数据播种所需的阴影属性。因此,它允许您传递包含所有实体属性的任何匿名或具体类型。

因此它试图反映传递对象的实际类型并找到属性Id。由于在您的情况下传递的单个对象的实际类型是List&lt;TEntity&gt;,当然它没有Id 属性,因此出现异常消息。

话虽如此,修复当然是调用正确的HasData 重载(使用IEnumerable&lt;object&gt; data):

modelBuilder.Entity(type).HasData((IEnumerable<object>)data);

【讨论】:

  • 你先生,是男人中的传奇。非常感谢。
  • 想象一下,如果List&lt;TEntity&gt; 拥有 Id 属性,你会从运行代码中获得什么乐趣。
  • 就是这样,谢谢!我不知道为什么在传递 3 个已知类型的数组时会调用 params object[] data 重载,所以它应该调用 params TEntity[] data 重载?
  • @ShahinDohan 没有params TEntity[] 重载AFAIK。如果你传递了 3 个 arrays,那么你肯定会点击 params object[]params 基本上允许您调用没有显式分配数组的方法,即 Foo(arg1, arg2, .., argN)Foo(new [] { arg1, arg2, ..., argN) }
  • @IvanStoev 实际上存在这样的重载,至少在 EF Core 3.1 中是这样。但是您对数组是正确的,当然它会选择对象重载,因为params TEntity[] 需要多个TEntity,而不是TEntity 的多个数组...我想我太累了:)
猜你喜欢
  • 2021-06-11
  • 2016-05-24
  • 2012-04-17
  • 2011-04-23
  • 2015-11-16
  • 2019-01-26
  • 1970-01-01
  • 2012-10-01
  • 1970-01-01
相关资源
最近更新 更多