我想简化代码以添加loadoptions和关联过滤,所以我创建了这个类。
class GraphQuery<T>
{
private IQueryable<T> query;
private DataLoadOptions load;
public GraphQuery(DataLoadOptions load, IQueryable<T> query)
{
this.load = load;
this.query = query;
}
public GraphQuery<T> Load(
Expression<Func<T, object>> expr,
Expression<Func<T, object>> filter)
{
load.LoadWith(expr);
load.AssociateWith(filter);
return this;
}
// more public methods ...
}
然后可以像这样使用:
var clients = Graph(db.Clients.Where(e => !e.Deleted))
.Load(e => e.ClientPersons,
e => e.ClientPersons.Where(j => !j.Person.Deleted));
但是,我看到e => e.ClientPersons
的重复非常简单。所以我想将上述用法减少到:
var clients = Graph(db.Clients.Where(e => !e.Deleted))
.Load(e => e.ClientPersons.Where(j => !j.Person.Deleted));
所以Load函数看起来应该像
public GraphQuery<T> Load(Expression<Func<T, object>> filter)
{
var expr = ... extract first part of the expression that represents the association property
load.LoadWith(expr);
load.AssociateWith(filter);
return this;
}
我从未使用linq表达式,除了在查询中使用它们
答案 0 :(得分:0)
我使用调试器来查看从表达式中可以获得的内容,并发现提取我需要的内容相当简单。我猜它不漂亮,但它完成了工作。如果有人提出改进建议 - 请发表评论。
private static LambdaExpression GetRootMemberExpression(LambdaExpression lambda1)
{
var expr = lambda1.Body;
while (!FindRoot(ref expr)) ;
if (!(expr is MemberExpression))
throw new Exception("MemberExpression required");
return Expression.Lambda(expr, (expr as MemberExpression).Expression as ParameterExpression);
}
private static bool FindRoot(ref Expression expr)
{
if (expr is MemberExpression)
return FindRoot(ref expr, (expr as MemberExpression).Expression);
if (expr.NodeType == ExpressionType.Call)
return FindRoot(ref expr, (expr as MethodCallExpression).Object);
throw new Exception("Unexpected Expression type encountered (" + expr.NodeType + ")");
}
private static bool FindRoot(ref Expression expr, Expression expr2)
{
if (expr2.NodeType == ExpressionType.Parameter)
return true;
expr = expr2;
return false;
}