В настоящее время, когда есть ошибка в конфигурации модели DBContext, мы получаем ошибку во время выполнения. Например:
Тип сущности 'MyObject' требует определения первичного ключа. Если вы намеревались использовать тип объекта без ключа, вызовите HasNoKey ().
Эта ошибка выдается при первом использовании EF Core в приложении. Я хотел бы проверить модель в модульном тесте.
Что я пробовал
Я заметил ModelValidator.Validate
в трассировке стека, поэтому я попробовал это:
[TestMethod]
public void MyDbContext_DoesNotThrowExceptions()
{
// Arrange
var myDbContext = CreateMyDbContext();
IModel model = myDbContext.Model;
var validator = new ModelValidator(new ModelValidatorDependencies(???,???)) // [EntityFrameworkInternal] public ModelValidatorDependencies([NotNull] ITypeMappingSource typeMappingSource,[NotNull] IMemberClassifier memberClassifier)
// Act
validator.Validate(model, ???); // public virtual void Validate(IModel model,IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
}
К сожалению, я сейчас не знаю, как создать ModelValidator
/ ModelValidatorDependencies
или что передать как IDiagnosticsLogger
- см. ???
в коде. Также [EntityFrameworkInternal]
дает мне идею, что у меня неправильный подход.
Кто-нибудь знает, как исправить этот модульный тест? (Путем создания ModelValidator
или с помощью другого подхода)
Сведения
Полная трассировка стека ошибки:
Test method Foo threw exception:
System.InvalidOperationException: The entity type 'MyEntity' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'.
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(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)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
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.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.Microsoft.EntityFrameworkCore.Internal.IDatabaseFacadeDependenciesAccessor.get_Dependencies()
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetFacadeDependencies(DatabaseFacade databaseFacade)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(DatabaseFacade databaseFacade, String sql, IEnumerable`1 parameters)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(DatabaseFacade databaseFacade, String sql, Object[] parameters)
at myCode
Решение
С Сом-твики (метод валидации EF Core 3 имеет 2 параметра), ответ Васила сработал для меня. У меня сейчас:
[TestMethod]
public void MyDbContext_DoesNotThrowExceptions()
{
// Arrange
var serviceProvider = CreateServiceProvider();
var validator = serviceProvider.GetService<IModelValidator>();
var context = serviceProvider.GetService<MyDbContext>();
var logger = serviceProvider.GetService<IDiagnosticsLogger<DbLoggerCategory.Model.Validation>>();
// Act
validator.Validate(context.Model, logger);
}
private static ServiceProvider CreateServiceProvider()
{
var serviceCollection = new ServiceCollection()
.AddEntityFrameworkSqlServer()
.AddDbContext<MyDbContext>((sp, options) => options
.UseSqlServer(new SqlConnection()));
return serviceCollection.BuildServiceProvider();
}