簡體   English   中英

如何在LINQ中動態創建Joins?

[英]How to dynamically create Joins in LINQ?

我正在嘗試在LINQ中動態創建Joins。 這個答案使我對從哪里開始有了很好的認識。 但是,特別是當“先行鍵”是int?時,我遇到了問題int? int作品)。 什么時候是int? 它將觸發異常。

我制作了一個簡單的LINQ to Objects示例來顯示問題。 為了運行我的示例,您將需要安裝動態linq Nuget軟件包,因為我將其用於DynamicExpression.ParseLambda方法。

這是觸發異常的代碼:

public class Contact
{
   public int Id { get; set; }

   public string Name { get; set; }
}

public class Address
{
   public int Id { get; set; }
   public int? ContactId { get; set; }

   public string Zip { get; set; }
}

class Program
{
   static void Main(string[] args)
   {
       var contacts = new List<Contact>();
       var addresses = new List<Address>();

       LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(typeof(Contact), null, "Id", new object[0]);
       LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(typeof(Address), null, "ContactId", new object[0]);
       ParameterExpression[] parameters = new ParameterExpression[] { Expression.Parameter(typeof(Contact), "outer"), Expression.Parameter(typeof(Address), "inner") };
       LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, "outer.Id", new object[0]);

       // BLOWS UP HERE
       var queryExpression = Expression.Call(
           typeof(Queryable), "Join",
           new Type[] { typeof(Contact), typeof(Address), typeof(int?), typeof(int) },
           contacts.AsQueryable().Expression, addresses.AsQueryable().Expression,
           Expression.Quote(outerSelectorLambda), Expression.Quote(innerSelectorLambda), Expression.Quote(resultsSelectorLambda));

       // it will not reach the following line
       var queryable = contacts.AsQueryable().Provider.CreateQuery(queryExpression);
   }
}

為了使以上代碼正常工作 ,只需替換兩次出現的int? 通過int 一切都會正常。 問題在於Address.ContactIdint?

問題是: 為什么會發生這種情況,我該如何解決?

例外信息(葡萄牙語):

System.InvalidOperationException was unhandled
 HResult=-2146233079
 Message=Nenhum método genérico 'Join' no tipo 'System.Linq.Queryable' é compatível com os argumentos e os argumentos de tipo fornecidos. Nenhum argumento de tipo deve ser fornecido se o método for não genérico. 
 Source=System.Core
 StackTrace:
      em System.Linq.Expressions.Expression.FindMethod(Type type, String methodName, Type[] typeArgs, Expression[] args, BindingFlags flags)
      em System.Linq.Expressions.Expression.Call(Type type, String methodName, Type[] typeArguments, Expression[] arguments)
      em problems.Program.Main(String[] args) na d:\POCs\problems\problems\Program.cs:linha 38
      em System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
      em System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
      em Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
      em System.Threading.ThreadHelper.ThreadStart_Context(Object state)
      em System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
      em System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
      em System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
      em System.Threading.ThreadHelper.ThreadStart()
 InnerException: 

問題是您的密鑰類型是int? ,但是用於創建鍵選擇器的ParseLambda方法正在為外鍵選擇器創建類型為Expression<Func<Contact, int>> 它沒有將結果映射到可為null的int。 然后,該函數與Join方法的簽名不兼容,因此將引發異常。

如果出於您的示例的考慮,如果對選擇器使用以下表達式,則它將正常工作:

Expression<Func<Contact, int?>> outerSelectorLambda = c => c.Id;

在查看ParseLambda的API時,您應該使用第二個參數指定lambda的返回類型,因此請不要將其保留為null

DynamicExpression.ParseLambda(typeof(Contact), typeof(int?),
    "Id", new object[0]);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM