如何使用表达式树编写 linq.join 来进行动态查询
How to write linq .join with expressions tree to do dynamic queries
我似乎无法在任何地方找到这个问题的答案...
objective 是找到一种使用表达式树语句执行 linq .join() 的方法。
所以...使用 Microsoft example:
class Person
{
public string Name { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
public static void JoinEx1()
{
Person magnus = new Person { Name = "Hedlund, Magnus" };
Person terry = new Person { Name = "Adams, Terry" };
Person charlotte = new Person { Name = "Weiss, Charlotte" };
Pet barley = new Pet { Name = "Barley", Owner = terry };
Pet boots = new Pet { Name = "Boots", Owner = terry };
Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
List<Person> people = new List<Person> { magnus, terry, charlotte };
List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };
// Join the list of Person objects and the list of Pet objects
// to create a list of person-pet pairs where each element is
// an anonymous type that contains the name of pet and the name
// of the person that owns the pet.
var query = people.AsQueryable().Join(pets,
person => person,
pet => pet.Owner,
(person, pet) =>
new { OwnerName = person.Name, Pet = pet.Name });
任何人都可以帮助我如何使用 Expression trees 执行 .join() 吗?
由于 Queryable.Join
是一种通用的静态方法,因此使用扩展方法查找所需的 MethodInfo
最简单:
public static class TypeExt {
public static MethodInfo GetMethod(this Type t, string methodName, int paramCount) =>
t.GetMethods().Where(mi => mi.Name == methodName && mi.GetParameters().Length == paramCount).Single();
}
Join
方法有五个参数(扩展方法将它们应用到的对象作为第一个参数传递),因此我们将一次构建它们 Expression
个。五个参数分别是IQueryable<>
、要连接的IEnumerable<>
、外键选择器lambda、内键选择器lambda和结果选择器lambda。
// Build Queryable.Join<TOuter,TInner,TKey,TResult> and use as query expression
// IQueryable<TOuter>
var arg0 = Expression.Constant(people.AsQueryable());
// IEnumerable<TInner>
var arg1 = Expression.Constant(pets);
// TOuter person
var arg2p = Expression.Parameter(people.GetType().GetGenericArguments()[0], "person");
// also TKey person
// Expression<Func<TOuter,TKey>>: person => person
var arg2 = Expression.Quote(Expression.Lambda(arg2p, arg2p));
// TInner pet
var arg3p = Expression.Parameter(pets.GetType().GetGenericArguments()[0], "pet");
// TKey pet.Owner
var arg3body = Expression.Property(arg3p, "Owner");
// Expression<Func<TInner,TKey>>: pet => pet.Owner
var arg3 = Expression.Quote(Expression.Lambda(arg3body, arg3p));
// TResult = typeof(new { string OwnerName , string Pet })
var anonymousType = (new { OwnerName = default(string), Pet = default(string) }).GetType();
// .ctor
var arg4Constructor = anonymousType.GetConstructors()[0];
// person.Name
var arg4PersonName = Expression.Property(arg2p, "Name");
// pet.Name
var arg4PetName = Expression.Property(arg3p, "Name");
var arg4Args = new[] { arg4PersonName, arg4PetName };
// new[] { .OwnerName, .Pet }
var arg4Members = anonymousType.GetProperties();
// new { OwnerName = person.Name, Pet = pet.Name }
var arg4body = Expression.New(arg4Constructor, arg4Args, arg4Members);
// Expression<Func<TOuter,TInner,TResult>>: (person,pet) => new { OwnerName = person.Name, Pet = pet.Name }
var arg4 = Expression.Quote(Expression.Lambda(arg4body, arg2p, arg3p));
注意:由于复杂的嵌套 lambda 闭包原因,每个 lambda 都被 Expression.Quote
包围,因此 Expression
编译器将知道 return 一个 Expression
树而不是一个代表。在此示例中,它没有区别。
现在使用扩展方法,您可以查找需要使用的 Join
,将其从通用方法实例化为您正在查询的类型的特定方法,并创建 Join
方法调用表达式:
var joinGenericMI = typeof(Queryable).GetMethod("Join", 5);
var joinMI = joinGenericMI.MakeGenericMethod(new[] { arg2p.Type, arg3p.Type, arg2p.Type, anonymousType });
var qExpr = Expression.Call(joinMI, arg0, arg1, arg2, arg3, arg4);
最后,您可以使用 Expression
创建一个 IQueryable<>
:
var q2 = people.AsQueryable().Provider.CreateQuery(qExpr);
我似乎无法在任何地方找到这个问题的答案...
objective 是找到一种使用表达式树语句执行 linq .join() 的方法。
所以...使用 Microsoft example:
class Person
{
public string Name { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
public static void JoinEx1()
{
Person magnus = new Person { Name = "Hedlund, Magnus" };
Person terry = new Person { Name = "Adams, Terry" };
Person charlotte = new Person { Name = "Weiss, Charlotte" };
Pet barley = new Pet { Name = "Barley", Owner = terry };
Pet boots = new Pet { Name = "Boots", Owner = terry };
Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
List<Person> people = new List<Person> { magnus, terry, charlotte };
List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };
// Join the list of Person objects and the list of Pet objects
// to create a list of person-pet pairs where each element is
// an anonymous type that contains the name of pet and the name
// of the person that owns the pet.
var query = people.AsQueryable().Join(pets,
person => person,
pet => pet.Owner,
(person, pet) =>
new { OwnerName = person.Name, Pet = pet.Name });
任何人都可以帮助我如何使用 Expression trees 执行 .join() 吗?
由于 Queryable.Join
是一种通用的静态方法,因此使用扩展方法查找所需的 MethodInfo
最简单:
public static class TypeExt {
public static MethodInfo GetMethod(this Type t, string methodName, int paramCount) =>
t.GetMethods().Where(mi => mi.Name == methodName && mi.GetParameters().Length == paramCount).Single();
}
Join
方法有五个参数(扩展方法将它们应用到的对象作为第一个参数传递),因此我们将一次构建它们 Expression
个。五个参数分别是IQueryable<>
、要连接的IEnumerable<>
、外键选择器lambda、内键选择器lambda和结果选择器lambda。
// Build Queryable.Join<TOuter,TInner,TKey,TResult> and use as query expression
// IQueryable<TOuter>
var arg0 = Expression.Constant(people.AsQueryable());
// IEnumerable<TInner>
var arg1 = Expression.Constant(pets);
// TOuter person
var arg2p = Expression.Parameter(people.GetType().GetGenericArguments()[0], "person");
// also TKey person
// Expression<Func<TOuter,TKey>>: person => person
var arg2 = Expression.Quote(Expression.Lambda(arg2p, arg2p));
// TInner pet
var arg3p = Expression.Parameter(pets.GetType().GetGenericArguments()[0], "pet");
// TKey pet.Owner
var arg3body = Expression.Property(arg3p, "Owner");
// Expression<Func<TInner,TKey>>: pet => pet.Owner
var arg3 = Expression.Quote(Expression.Lambda(arg3body, arg3p));
// TResult = typeof(new { string OwnerName , string Pet })
var anonymousType = (new { OwnerName = default(string), Pet = default(string) }).GetType();
// .ctor
var arg4Constructor = anonymousType.GetConstructors()[0];
// person.Name
var arg4PersonName = Expression.Property(arg2p, "Name");
// pet.Name
var arg4PetName = Expression.Property(arg3p, "Name");
var arg4Args = new[] { arg4PersonName, arg4PetName };
// new[] { .OwnerName, .Pet }
var arg4Members = anonymousType.GetProperties();
// new { OwnerName = person.Name, Pet = pet.Name }
var arg4body = Expression.New(arg4Constructor, arg4Args, arg4Members);
// Expression<Func<TOuter,TInner,TResult>>: (person,pet) => new { OwnerName = person.Name, Pet = pet.Name }
var arg4 = Expression.Quote(Expression.Lambda(arg4body, arg2p, arg3p));
注意:由于复杂的嵌套 lambda 闭包原因,每个 lambda 都被 Expression.Quote
包围,因此 Expression
编译器将知道 return 一个 Expression
树而不是一个代表。在此示例中,它没有区别。
现在使用扩展方法,您可以查找需要使用的 Join
,将其从通用方法实例化为您正在查询的类型的特定方法,并创建 Join
方法调用表达式:
var joinGenericMI = typeof(Queryable).GetMethod("Join", 5);
var joinMI = joinGenericMI.MakeGenericMethod(new[] { arg2p.Type, arg3p.Type, arg2p.Type, anonymousType });
var qExpr = Expression.Call(joinMI, arg0, arg1, arg2, arg3, arg4);
最后,您可以使用 Expression
创建一个 IQueryable<>
:
var q2 = people.AsQueryable().Provider.CreateQuery(qExpr);