繁体   English   中英

种子抛出“无值提供”异常的添加迁移

[英]Add-Migration with seeds throwing “no value provided” exception

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

为了使该过程尽可能地动态,我通过标识名称空间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)

您将陷入典型的params object[]陷阱中。

HasData方法有2个重载-一个重载params object[] data和一个重载IEnumerable<object> data 由于进行了反射调用,因此data变量的类型为object 因此,您正在使用包含data 单个项目object[]来调用第一个重载。

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

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

HasData ,修复程序当然是调用正确的HasData重载(使用IEnumerable<object> data ):

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM