为 Entity Framework 多对多关系构建表达式树?
Build an Expression Tree for Entity Framework Many to Many relationship?
我正在为以下结构编写代码:
3 桌
Table "Book", "BookAuthor" and "Author".
我现在想构建一个 ExpressionTree 以获得以下 Linq 结果:
_ent.Book.Where(c => c.BookAuthor.Any(cd => cd.Author.AuthorName == "test"));
我的问题是到达 cd.Author.AuthorName
(或类似)的最后一个表达式。
我当前的代码:
private MethodCallExpression BuiltMethodCall(IQueryable _query, string CustTypeID, Type _ParentObjType,
Type _ChildObjType, string strChildObj, string strChildCol)
{
//This function will build a dynamic linq expression tree representing the ling calls of:
//Book.Where(c => c.BookAuthor.Any(cd => cd.Author = custTypeID))
ConstantExpression value = Expression.Constant(CustTypeID);
//Build the outer part of the Where clause
ParameterExpression parameterOuter = Expression.Parameter(_ParentObjType, "c");
MemberExpression propertyOuter = Expression.Property(parameterOuter, strChildObj);
//Build the comparison inside of the Any clause
ParameterExpression parameterInner = Expression.Parameter(_ChildObjType, "cd");
MemberExpression propertyInner = Expression.Property(parameterInner, strChildCol);
BinaryExpression comparison = Expression.Equal(propertyInner, value);
LambdaExpression lambdaInner = Expression.Lambda(comparison, parameterInner);
//Create Generic Any Method
Func<MethodInfo, bool> methodLambda = m => m.Name == "Any" && m.GetParameters().Length == 2;
MethodInfo method = typeof(Enumerable).GetMethods().Where(methodLambda).Single()
.MakeGenericMethod(_ChildObjType);
//Create the Any Expression Tree and convert it to a Lambda
MethodCallExpression callAny = Expression.Call(method, propertyOuter, lambdaInner);
LambdaExpression lambdaAny = Expression.Lambda(callAny, parameterOuter);
//Build the final Where Call
MethodCallExpression whereCall = Expression.Call(typeof(Queryable), "Where",
new Type[] { _query.ElementType }, new Expression[]
{
_query.Expression,
Expression.Quote(lambdaAny)
});
return whereCall;
}
如果我没理解错的话,你问的是如何创建嵌套的 属性 访问器表达式。
借助 String.Split
and Enumerable.Aggregate
方法非常简单。
这是一个自定义扩展方法,可以用作 Expression.Property
方法替换:
public static partial class ExpressionExtensions
{
public static MemberExpression Property(this Expression instance, string path)
{
return (MemberExpression)path.Split('.').Aggregate(instance, Expression.Property);
}
}
它可以正确处理在 string
中使用 .
分隔符(例如 "BookAuthor"
或 "Author.AuthorName"
)编码的简单属性和嵌套属性。
所以不用
MemberExpression propertyOuter = Expression.Property(parameterOuter, strChildObj);
和
MemberExpression propertyInner = Expression.Property(parameterInner, strChildCol);
你可以放心使用
MemberExpression propertyOuter = parameterOuter.Property(strChildObj);
和
MemberExpression propertyInner = parameterInner.Property(strChildCol);
我正在为以下结构编写代码:
3 桌
Table "Book", "BookAuthor" and "Author".
我现在想构建一个 ExpressionTree 以获得以下 Linq 结果:
_ent.Book.Where(c => c.BookAuthor.Any(cd => cd.Author.AuthorName == "test"));
我的问题是到达 cd.Author.AuthorName
(或类似)的最后一个表达式。
我当前的代码:
private MethodCallExpression BuiltMethodCall(IQueryable _query, string CustTypeID, Type _ParentObjType,
Type _ChildObjType, string strChildObj, string strChildCol)
{
//This function will build a dynamic linq expression tree representing the ling calls of:
//Book.Where(c => c.BookAuthor.Any(cd => cd.Author = custTypeID))
ConstantExpression value = Expression.Constant(CustTypeID);
//Build the outer part of the Where clause
ParameterExpression parameterOuter = Expression.Parameter(_ParentObjType, "c");
MemberExpression propertyOuter = Expression.Property(parameterOuter, strChildObj);
//Build the comparison inside of the Any clause
ParameterExpression parameterInner = Expression.Parameter(_ChildObjType, "cd");
MemberExpression propertyInner = Expression.Property(parameterInner, strChildCol);
BinaryExpression comparison = Expression.Equal(propertyInner, value);
LambdaExpression lambdaInner = Expression.Lambda(comparison, parameterInner);
//Create Generic Any Method
Func<MethodInfo, bool> methodLambda = m => m.Name == "Any" && m.GetParameters().Length == 2;
MethodInfo method = typeof(Enumerable).GetMethods().Where(methodLambda).Single()
.MakeGenericMethod(_ChildObjType);
//Create the Any Expression Tree and convert it to a Lambda
MethodCallExpression callAny = Expression.Call(method, propertyOuter, lambdaInner);
LambdaExpression lambdaAny = Expression.Lambda(callAny, parameterOuter);
//Build the final Where Call
MethodCallExpression whereCall = Expression.Call(typeof(Queryable), "Where",
new Type[] { _query.ElementType }, new Expression[]
{
_query.Expression,
Expression.Quote(lambdaAny)
});
return whereCall;
}
如果我没理解错的话,你问的是如何创建嵌套的 属性 访问器表达式。
借助 String.Split
and Enumerable.Aggregate
方法非常简单。
这是一个自定义扩展方法,可以用作 Expression.Property
方法替换:
public static partial class ExpressionExtensions
{
public static MemberExpression Property(this Expression instance, string path)
{
return (MemberExpression)path.Split('.').Aggregate(instance, Expression.Property);
}
}
它可以正确处理在 string
中使用 .
分隔符(例如 "BookAuthor"
或 "Author.AuthorName"
)编码的简单属性和嵌套属性。
所以不用
MemberExpression propertyOuter = Expression.Property(parameterOuter, strChildObj);
和
MemberExpression propertyInner = Expression.Property(parameterInner, strChildCol);
你可以放心使用
MemberExpression propertyOuter = parameterOuter.Property(strChildObj);
和
MemberExpression propertyInner = parameterInner.Property(strChildCol);