【问题标题】:EF Core 7.0 - OwnsOne throws NRE internallyEF Core 7.0 - OwnsOne 在内部抛出 NRE
【发布时间】:2023-02-16 06:36:23
【问题描述】:

使用 EntityFrameworkCore v7.0.0(带有 SQL Server 适配器)

我试图通过调用 .OwnsOne(...) 将拥有的实体附加到主体实体,但是 EFCore 在尝试生成影子外键时在内部生成 NullReferenceException

代码如下:

public class ProductId : ValueObject
{
    public Guid Value { get; private set; }

    private ProductId(Guid value)
    {
        Value = value;
    }

    public static ProductId Create(Guid value)
    {
        return new ProductId(value);
    }
}

public class ProductName : ValueObject 
{
    public string Value { get; private set; }

    public ProductName(string value)
    {
        Value = value;
    }

    // ValueObject overrides
}

public abstract class AggregateRoot<TId> where TId : notnull
{
    // ... ctor
}

public class Product : AggregateRoot<ProductId>
{
    private Product() { }

    public ProductName Name { get; private set; }
}

以及IEntityTypeConfiguration&lt;&gt;的以下实现:

public class ProductConfiguration : IEntityTypeConfiguration<Product>
{
    public void Configure(EntityTypeBuilder<Product> builder)
    {
        builder.ToTable("Products");

        builder.HasKey(p => p.Id);

        builder.Property(p => p.Id)
            .ValueGeneratedNever()
            .HasConversion(
                id => id.Value,
                value => ProductId.Create(value));

        builder.OwnsOne(
            p => p.Name,
            navBuilder =>
            {
                navBuilder.Property(x => x.Value)
                    .HasColumnName(nameof(Product.Name))
                    .IsRequired();
            });
    }
}

发生的 NRE 的 EF Core 堆栈跟踪:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalEntityTypeBuilder.CreateForeignKey(InternalEntityTypeBuilder principalEntityTypeBuilder, IReadOnlyList`1 dependentProperties, Key principalKey, String propertyBaseName, Nullable`1 required, ConfigurationSource configurationSource)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalEntityTypeBuilder.HasRelationship(EntityType targetEntityType, Nullable`1 navigationToTarget, Nullable`1 inverseNavigation, Nullable`1 setTargetAsPrincipal, ConfigurationSource configurationSource, Nullable`1 required)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalEntityTypeBuilder.HasOwnership(EntityType targetEntityType, MemberIdentity& navigation, Nullable`1 inverse, ConfigurationSource configurationSource)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalEntityTypeBuilder.Microsoft.EntityFrameworkCore.Metadata.Builders.IConventionEntityTypeBuilder.HasOwnership(IConventionEntityType targetEntityType, MemberInfo navigation, Boolean fromDataAnnotation)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.RelationshipDiscoveryConvention.CreateRelationships(IEnumerable`1 relationshipCandidates, IConventionEntityTypeBuilder entityTypeBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.RelationshipDiscoveryConvention.Process(IConventionEntityType entityType, String navigationName, MemberInfo memberInfo, IConventionContext context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.RelationshipDiscoveryConvention.ProcessNavigationRemoved(IConventionEntityTypeBuilder sourceEntityTypeBuilder, IConventionEntityTypeBuilder targetEntityTypeBuilder, String navigationName, MemberInfo memberInfo, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnNavigationRemoved(IConventionEntityTypeBuilder sourceEntityTypeBuilder, IConventionEntityTypeBuilder targetEntityTypeBuilder, String navigationName, MemberInfo memberInfo)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnNavigationRemovedNode.Run(ConventionDispatcher dispatcher)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.DelayedConventionScope.Run(ConventionDispatcher dispatcher)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run()
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Dispose()
   at Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder`1.OwnsOneBuilder[TRelatedEntity](TypeIdentity ownedType, MemberIdentity navigation)
   at Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder`1.OwnsOne[TRelatedEntity](Expression`1 navigationExpression, Action`1 buildAction)
   at CustomNamespace.Persistence.ProductConfiguration.Configure(EntityTypeBuilder`1 builder) in C:\CustomNamespace\Persistence\ProductConfiguration.cs:line 27
   at Microsoft.EntityFrameworkCore.ModelBuilder.ApplyConfiguration[TEntity](IEntityTypeConfiguration`1 configuration)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.EntityFrameworkCore.ModelBuilder.ApplyConfigurationsFromAssembly(Assembly assembly, Func`2 predicate)
   at CustomNamespace.Persistence.DbContext.OnModelCreating(ModelBuilder modelBuilder) in C:\CustomNamespace\Persistence\DbContext.cs:line 16
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(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 callSite, 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 callSite, 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 callSite, 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 callSite, 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 callSite, 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 callSite, 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__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.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_ContextServices()
   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.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, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Exception has been thrown by the target of an invocation.

我尝试通过 EFCore OwnsOne 实现进行研究和调试,但未能找到原因。我有其他遵循相同逻辑的实体,并且一切都按预期工作。

【问题讨论】:

  • EF Core 7 本身不会抛出OwnsOne。不过,您的代码显示了在 ORM 中使用 DDD 概念的尝试。 DDD 指的是域对象,而不是 ORM。实体不是聚合根,主键类型不是 DDD 值对象。在特定用例中,例如电子商务应用程序或订单应用程序,聚合根是组合该特定用例中使用的所有订单、订单项目、客户、产品、价格等的对象。那可能是Cart。使用 ORM 消除了构建它所需的 95% 的代码,但不会使 ORM 实体成为 DDD 根
  • 而不是使用可能不需要的概念根本在您的应用程序中,尝试单独使用 EF Core第一的.现在,您正在将 ORM 概念泄漏到业务层(因为您加载了 ORM 实体),并将业务概念泄漏到 ORM。
  • 我想为代码提供一些,在领域层应用 DDD 原则并不重要。重要的是 OwnsOne 在尝试将 ProductName 拥有的实体附加到主体实体时抛出 NullReferenceException - Product
  • 如果这样的基本功能不起作用,那么所有示例都不会起作用,所有使用 EF Core 的开发人员都会注意到。 ProductName 不是实体,而是财产。您仍在尝试使 ORM 像 DDD 一样工作,对错误的事物使用错误的术语和函数。消除所有尝试使用像 ValueObjectAggregateRoot 类这样的 DDD 术语,使用普通的旧 C# 对象并检查 OwnsOne 是否有效——假设它有意义。只有这样才能尝试使事情变得更有趣
  • 我应该能够将 ProductName ValueObject 保留为拥有的类型——即将 Product.ProductName.Value 映射到 SQL 表 [Products] - [Name] 列。我不明白为什么我的域层的结构很重要。我并不是说 EFCore 的基本功能不起作用 - 只是它在这种特殊情况下对我不起作用,尽管我有其他实体实施相同的原则并且它按预期工作。

标签: .net entity-framework-core


【解决方案1】:

花了 19 天才弄明白。我可能是错的。就我而言,我试图定义一个具有多个角色的用户并遇到相同的错误。然后今天,将 User 更改为 FarmUser 并将 Role 更改为 FarmRole 后,问题就解决了。反射有可能首先尝试解决预定义的问题。

【讨论】:

    猜你喜欢
    • 2018-08-28
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    • 2023-01-24
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多