Я пытаюсь создать пакет, который поможет заполнить базы данных данными из файлов 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)