【问题标题】:How to dynamically create Joins in LINQ?如何在 LINQ 中动态创建联接?
【发布时间】:2013-12-02 18:29:48
【问题描述】:

我正在尝试在 LINQ 中动态创建联接。 This answer 让我很好地了解了从哪里开始。但是,当“外键”是int? 时,我遇到了一个问题 (int 有效)。当它是int? 时会触发异常。

我制作了一个简单的 LINQ to Objects 示例来说明问题。为了运行我的示例,您需要install the dynamic linq Nuget package,因为我将它用于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? 的2 次出现替换为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: 

【问题讨论】:

    标签: c# .net linq linq-to-objects


    【解决方案1】:

    问题在于您的键类型是int?,但您用于创建键选择器的ParseLambda 方法正在为您的外部键选择器创建Expression&lt;Func&lt;Contact, int&gt;&gt; 类型的表达式。它没有将结果映射到可为空的 int。该函数与Join 方法的签名不兼容,因此会引发异常。

    为了您的示例,如果您使用以下表达式作为选择器,它将正常工作:

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

    查看ParseLambda 的API,您应该使用第二个参数来指定lambda 的返回类型,所以不要留下它null

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

    【讨论】:

    • 该死的@Sevry!我和我的同事花了很多时间试图弄清楚这一点。太感谢了!你摇滚!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 2018-01-16
    • 1970-01-01
    相关资源
    最近更新 更多