Linq2db中QueryExpressionMethod关联报空值错误,键关联正常
我尝试将Linq2db中基于键的Association关联方式改为QueryExpressionMethod形式(用于优化其他代码),但遇到了问题:
可正常运行的代码
[Association( CanBeNull = true, ThisKey = nameof( AccountId ), OtherKey = nameof( Common.Account.AccountId ) )] public List<AccountPayment> AccountPayments { get; set; }
无法运行的代码
[Association( CanBeNull = true, QueryExpressionMethod = nameof (LatestPaymentImpl) )] public List<AccountPayment> AccountPayments { get; set; } public static Expression<Func<Account, IDataContext, IQueryable<Repositories.Models.Common.AccountPayment>>> LatestPaymentImpl() { return ( ap, db ) => db.GetTable<AccountPayment>().Where( acc => acc.AccountId == ap.AccountId ); }
抛出的异常信息
"reason": "ArgumentException",
"message": "Value cannot be null.\r\nParameter name: arg0",
"status": "badRequest",
"stackTrace": " at System.Linq.Expressions.Expression.Call(Expression instance,
MethodInfo method, Expression arg0, Expression arg1, Expression
arg2)\r\n at
LinqToDB.Linq.Builder.TableBuilder.AssociatedTableContext.GetAssociationQueryExpression(Expression
dataContextExpr, Expression parentObjExpression, Type parentType,
Expression parentTableExpression, LambdaExpression queryMethod)\r\n
at
LinqToDB.Linq.Builder.TableBuilder.AssociatedTableContext..ctor(ExpressionBuilder
builder, TableContext parent, AssociationDescriptor association)\r\n
at
LinqToDB.Linq.Builder.TableBuilder.TableContext.b__71_6(AssociationDescriptor
a)\r\n at
System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()\r\n at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1
source)\r\n at
LinqToDB.Linq.Builder.TableBuilder.TableContext.GetAssociation(Expression
expression, Int32 level)\r\n at
LinqToDB.Linq.Builder.TableBuilder.TableContext.GetAssociation(Expression
expression, Int32 level)
环境信息
- Linq2db版本:2.7.0
涉及的实体类代码
Account类
[Table( Name = "Account", Schema = "Common" )] public class Account : ISoftDeletableRepositoryModel { #region Members [Column( "AccountId" ), Identity, PrimaryKey] public Guid AccountId { get; set; } [Column( "Deleted", SkipOnUpdate = true ), NotNull] public bool Deleted { get; set; } [Column( "Name" ), NotNull] public string Name { get; set; } [Association( CanBeNull = true, ThisKey = nameof( AccountId ), OtherKey = nameof( Security.UserAccount.AccountId ) )] public UserAccount UserAccount { get; set; } [Association( CanBeNull = true, ThisKey = nameof( AccountId ), OtherKey = nameof( Common.Account.AccountId ) )] public List<AccountPayment> LatestAccountPayment { get; set; } }
AccountPayment类
[Table( Name = "AccountPayment", Schema = "Common" )] public class AccountPayment : ISoftDeletableRepositoryModel { #region Members [Column( "AccountPaymentId" ), Identity, PrimaryKey] public Guid AccountPaymentId { get; set; } [Column( "Deleted", SkipOnUpdate = true ), NotNull] public bool Deleted { get; set; } [Column( "AccountId" ), NotNull] public Guid AccountId { get; set; } [Column( "PackageId" ), Nullable] public Guid? PackageId { get; set; } [Column( "Provider" ), NotNull] public string Provider { get; set; } [Column( "CustomerId" ), Nullable] public string CustomerId { get; set; } [Column( "SubscriptionId" ), Nullable] public string SubscriptionId { get; set; } [Column( "PaymentMethodToken" ), Nullable] public string PaymentMethodToken { get; set; } [Column( "Status" ), NotNull] public string Status { get; set; } [Column( "CreatedOn" ), NotNull] public DateTime CreatedOn { get; set; } [Column( "ValidUntil" ), Nullable] public DateTime? ValidUntil { get; set; } [Column( "CanceledOn" ), Nullable] public DateTime? CanceledOn { get; set; } #endregion Members #region Associations [Association( CanBeNull = true, ThisKey = nameof( AccountId ), OtherKey = nameof( Common.Account.AccountId ) )] public Account Account { get; set; } [Association( CanBeNull = true, ThisKey = nameof( PackageId ), OtherKey = nameof( Sales.Package.PackageId ) )] public Package Package { get; set; } #endregion Associations }
查询示例代码
query = from q in query join pa in db.ProgramAssigns on new { c = q.ProgramId, s = identityContext.UserId } equals new { c = pa.ProgramId, s = pa.AssigneeId } into paa from pa in paa.DefaultIfEmpty() where q.Deleted == false && ( pa != null && pa.Assigner.UserAccount.Account.LatestAccountPayment != null && pa.Assigner.UserAccount.Account.LatestAccountPayment.OrderByDescending(x => x.ValidUntil).FirstOrDefault().ValidUntil > DateTime.Now ) select q;
两种实现逻辑完全一致,但我不清楚该如何排查这个异常问题。
内容的提问来源于stack exchange,提问作者galaxyfreak

