如何创建动态LINQ连接扩展方法
有一个动态扩展方法库,作为一个示例发布。我想用join方法扩展它。以下代码在运行时因参数未匹配异常而失败。问题在哪里如何创建动态LINQ连接扩展方法,linq,linq-to-sql,c#-3.0,linq-to-entities,linq-to-objects,Linq,Linq To Sql,C# 3.0,Linq To Entities,Linq To Objects,有一个动态扩展方法库,作为一个示例发布。我想用join方法扩展它。以下代码在运行时因参数未匹配异常而失败。问题在哪里 public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerSelector, string innerSelector, string resultsSelector,
public static IQueryable Join(this IQueryable outer, IEnumerable inner,
string outerSelector, string innerSelector, string resultsSelector,
params object[] values)
{
if (inner == null)
throw new ArgumentNullException("inner");
if (outerSelector == null)
throw new ArgumentNullException("outerSelector");
if (innerSelector == null)
throw new ArgumentNullException("innerSelector");
if (resultsSelector == null)
throw new ArgumentNullException("resultsSelctor");
LambdaExpression outerSelectorLambda =
DynamicExpression.ParseLambda(outer.ElementType, null,
outerSelector, values);
LambdaExpression innerSelectorLambda =
DynamicExpression.ParseLambda(inner.AsQueryable().ElementType,
null, innerSelector, values);
ParameterExpression[] parameters = new ParameterExpression[] {
Expression.Parameter(outer.ElementType, "outer"),
Expression.Parameter(inner.AsQueryable().ElementType,
"inner")
};
LambdaExpression resultsSelectorLambda =
DynamicExpression.ParseLambda(parameters, null,
resultsSelector, values);
return outer.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Join", new Type[] {
outer.ElementType,
inner.AsQueryable().ElementType,
outerSelectorLambda.Body.Type,
innerSelectorLambda.Body.Type,
resultsSelectorLambda.Body.Type
},
outer.Expression, inner.AsQueryable().Expression,
Expression.Quote(outerSelectorLambda),
Expression.Quote(innerSelectorLambda),
Expression.Quote(resultsSelectorLambda))
);
}
我现在自己修好了。向CreateQuery(…)调用传递太多参数是一个小学生错误。将以下代码粘贴到动态联接扩展方法的DynamicQueryable类中的Dynamic.cs文件中。您可以在找到DynamicQuery示例项目的源代码。
享受吧
public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values)
{
if (inner == null) throw new ArgumentNullException("inner");
if (outerSelector == null) throw new ArgumentNullException("outerSelector");
if (innerSelector == null) throw new ArgumentNullException("innerSelector");
if (resultsSelector == null) throw new ArgumentNullException("resultsSelctor");
LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(outer.ElementType, null, outerSelector, values);
LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(inner.AsQueryable().ElementType, null, innerSelector, values);
ParameterExpression[] parameters = new ParameterExpression[] {
Expression.Parameter(outer.ElementType, "outer"), Expression.Parameter(inner.AsQueryable().ElementType, "inner") };
LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, resultsSelector, values);
return outer.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Join",
new Type[] {outer.ElementType, inner.AsQueryable().ElementType, outerSelectorLambda.Body.Type, resultsSelectorLambda.Body.Type },
outer.Expression, inner.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), Expression.Quote(innerSelectorLambda), Expression.Quote(resultsSelectorLambda)));
}
//The generic overload.
public static IQueryable<T> Join<T>(this IQueryable<T> outer, IEnumerable<T> inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values)
{
return (IQueryable<T>)Join((IQueryable)outer, (IEnumerable)inner, outerSelector, innerSelector, resultsSelector, values);
}
公共静态IQueryable联接(此IQueryable外部、IEnumerable内部、字符串外部选择器、字符串内部选择器、字符串结果选择器、参数对象[]值)
{
如果(inner==null)抛出新的ArgumentNullException(“inner”);
如果(outerSelector==null)抛出新的ArgumentNullException(“outerSelector”);
如果(innerSelector==null)抛出新的ArgumentNullException(“innerSelector”);
如果(resultsSelector==null)抛出新的ArgumentNullException(“resultsSelector”);
LambdaExpression outerSelectorLambda=DynamicExpression.ParseLambda(outer.ElementType,null,outerSelector,value);
LambdaExpression innerSelectorLambda=DynamicExpression.ParseLambda(inner.AsQueryable().ElementType,null,innerSelector,values);
ParameterExpression[]参数=新的ParameterExpression[]{
Expression.Parameter(outer.ElementType,“outer”)、Expression.Parameter(inner.AsQueryable().ElementType,“inner”)};
LambdaExpression resultsSelectorLambda=DynamicExpression.ParseLambda(参数,null,结果选择器,值);
返回outer.Provider.CreateQuery(
表情,打电话(
类型(可查询),“加入”,
新类型[]{outer.ElementType,inner.AsQueryable().ElementType,outerSelectorLambda.Body.Type,resultsSelectorLambda.Body.Type},
Expression,inner.AsQueryable().Expression,Expression.Quote(outerSelectorLambda),Expression.Quote(innerSelectorLambda),Expression.Quote(resultsSelectorLambda));
}
//通用重载。
公共静态IQueryable联接(此IQueryable外部、IEnumerable内部、字符串外部选择器、字符串内部选择器、字符串结果选择器、参数对象[]值)
{
返回(IQueryable)联接((IQueryable)外部,(IEnumerable)内部,外部选择器,内部选择器,结果选择器,值);
}
以下是一些示例代码,显示了多列上的联接。使用datatable和datarows,您需要始终通过索引器访问字段
DataTable t1 = new DataTable();
t1.Columns.Add("FundId", typeof(int));
t1.Columns.Add("Date", typeof(DateTime));
t1.Columns.Add("CodeA", typeof(string));
t1.Rows.Add(1, new DateTime(2010, 01, 01), "A1");
t1.Rows.Add(2, new DateTime(2010, 01, 01), "A2");
t1.Rows.Add(3, new DateTime(2010, 01, 01), "A3");
DataTable t2 = new DataTable();
t2.Columns.Add("FundId", typeof(int));
t2.Columns.Add("Date", typeof(DateTime));
t2.Columns.Add("CodeB", typeof(string));
t2.Rows.Add(1, new DateTime(2010, 01, 01), "B1");
t2.Rows.Add(2, new DateTime(2010, 01, 01), "B2");
t2.Rows.Add(3, new DateTime(2010, 01, 01), "B3");
IQueryable outerTable = t1.AsEnumerable().AsQueryable();
IEnumerable innerTable = t2.AsEnumerable();
var query = outerTable.Join
(
innerTable,
"new(get_Item(0) as FundId, get_Item(1) as Date)",
"new(get_Item(0) as FundId, get_Item(1) as Date)",
"new(outer.get_Item(0) as FundId, outer.get_Item(2) as CodeA, inner.get_Item(2) as CodeB)"
);
您可以安装System.Linq.Dynamic.Core- 这使得join方法与其他各种helper方法一起实现 使用此库,您可以按以下方式进行简单连接
myContext.TableA.Join(myContext.TableB,'Id','TableAId','outer',null)
在结果选择器中,外部和内部是访问联接结果的关键字
使用具有多个属性的键和/或选择具有多个属性的结果可以通过以下方式完成
myContext.TableA.Join(myContext.TableB,'new(Id为key1,code为key2)'new(TableAId为key1,AnotherCol为key2)'new(outer.Id,inner.Desc)'null)
您能粘贴准确的错误消息吗?您能发布一个使用Join的示例吗。我很想用它,但我在LINQ是个新手。谢谢。嘿,你知道这本书吗?我在2018年的“实体框架核心的现代数据访问”中发现了它。用法示例如下:此代码的简单用法如下:var result=myDbContext.Person.Join(myDbContext.Roles),“new(Id作为firstKey,SomeOtherId作为secondKey)”,“new(PersonId作为firstKey,AlternativeId作为secondKey)”,“new(PersonId作为firstKey,AlternativeId作为secondKey)”(内部为r,外部为p);
请注意,如果它在多个列上连接,如果它们的名称不相同,则必须使用“as[somekey]”,否则将发生错误。此外,在结果选择器中,您还可以使用关键字“outer”和“inner”如果我想在Join中比较不区分大小写的字符串,该如何实现?如果我的表数也是动态的,该如何实现?这并不能回答问题。这里您使用的是Linq提供的Join方法,问题是关于创建此方法,因为Linq尚未提供该方法。