【问题标题】:Reusing a foreign key for multiple navigation properties on other models在其他模型上为多个导航属性重用外键
【发布时间】:2020-11-03 18:37:50
【问题描述】:

这是a corresponding github issue on the EF Core repo的交叉发帖。


直到polymorphic relations can be supported,我正在尝试采用现有模式并从中创建一些有用的导航属性。不幸的是,我在许多方面都受到了挫败,尽管感觉我能得到的最接近的方法是通过以下方式:

    public class Entitlement
    {
        public Guid Id { get; set; }
        public Guid EntitleableId { get; set; }
    }

    public class Tenant
    {
        public Guid Id { get; set; }

        public ICollection<Entitlement> AssignedEntitlements { get; set; }
    }

    // note: Consider User and Firm the same as tenant in this example.
            // ...

            modelBuilder
                .Entity<Tenant>()
                .HasMany((tenant) => tenant.AssignedEntitlements)
                .WithOne()
                .IsRequired(true)
                .HasForeignKey((entitlement) => entitlement.EntitleableId)
                .HasPrincipalKey((tenant) => tenant.Id);

            modelBuilder
                .Entity<Firm>()
                .HasMany((firm) => firm.AssignedEntitlements)
                .WithOne()
                .IsRequired(true)
                .HasForeignKey((entitlement) => entitlement.EntitleableId)
                .HasPrincipalKey((firm) => firm.Id);

            modelBuilder
                .Entity<User>()
                .HasMany((user) => user.AssignedEntitlements)
                .WithOne()
                .IsRequired(true)
                .HasForeignKey((entitlement) => entitlement.EntitleableId)
                .HasPrincipalKey((user) => user.Id);

            // ...

使用类似的东西时我似乎无法检索任何东西:

dbContext.Tenants.Include((t) => t.AssignedEntitlements);

实体框架生成有效查询 (.ToQueryString()):

SELECT t.id, t.created_at, t."default", t.deleted_at, t.label, t.name, t.updated_at, e.id, e.created_at, e.entitleable_id, e.entitleable_type, e.feature, e.source_id, e.source_type, e.updated_at
FROM tenants AS t
         LEFT JOIN entitlements AS e ON t.id = e.entitleable_id
ORDER BY t.id, e.id

运行生成的 SQL 会返回正确的数据,但任何尝试在查询对象上运行 .First(), FirstOrDefault(), etc... 似乎都会导致问题:

System.InvalidOperationException: Sequence contains no matching element
   at System.Linq.ThrowHelper.ThrowNoMatchException()
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
   at MyProject.Conventions.Feature..ctor(String name)
   at lambda_method374(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.<PopulateIncludeCollection>g__ProcessCurrentElementRow|60_0[TIncludingEntity,TIncludedEntity](<>c__DisplayClass60_0`2& )
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.PopulateIncludeCollection[TIncludingEntity,TIncludedEntity](Int32 collectionId, QueryContext queryContext, DbDataReader dbDataReader, SingleQueryResultCoordinator resultCoordinator, Func`3 parentIdentifier, Func`3 outerIdentifier, Func`3 selfIdentifier, IReadOnlyList`1 parentIdentifierValueComparers, IReadOnlyList`1 outerIdentifierValueComparers, IReadOnlyList`1 selfIdentifierValueComparers, Func`5 innerShaper, INavigationBase inverseNavigation, Action`2 fixup, Boolean trackingQuery)
   at lambda_method376(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at lambda_method377(Closure , QueryContext )
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
   at MyProject.Global.Api.Controller.TestController.Test(MyProjectGlobalContext context) in /home/me/Development/MyProject/global/MyProject.Global.Api/src/Controller/TestController.cs:line 19
   at lambda_method289(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

【问题讨论】:

  • 所以使用FirstOrDefault(),如果记录集中没有项目,First() 会抛出异常。
  • 不起作用,以同样的错误结束。我也已经提到:“运行生成的 SQL 会返回正确的数据...” 所以我们这里不处理无结果问题。
  • 请继续阅读我写的内容。我不只是将它留在Include,我所写的其余内容都建立在它之上并解释了我的工作。
  • 对不起,我明白了。什么是MyProject.Conventions.Feature?构造函数中的异常。
  • 啊哈! @SvyatoslavDanyliv,你发现了我的错误!非常感谢。你想发布一个正确的答案让我接受吗?

标签: entity-framework-core foreign-keys navigation-properties


【解决方案1】:

看起来您的代码会导致此异常。 MyProject.Conventions.Feature 构造函数包含为某些空记录集调用 First 扩展的代码。

【讨论】:

  • 是的,我有一个自定义值类型在其构造函数中失败,EF/LINQ 正在吞噬我的异常。另外,我很讨厌堆栈跟踪。谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-06
  • 2020-09-01
  • 2016-01-09
相关资源
最近更新 更多