[英]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.ContactId
为int?
。
问题是: 为什么会发生这种情况,我该如何解决? 。
例外信息(葡萄牙语):
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.