动态创建包含子查询的Linq表达式 [英] Creating a Linq expression dynamically containing a subquery
问题描述
我最近遇到了一个问题,该问题是在运行时动态创建Linq表达式.我发现的大多数示例都涉及相当简单的任务,即仅将给定数据库实体的一个属性与单个参数进行比较.像这样:
I recently stumpled upon the problem to dynamically create Linq expressions during runtime. Most examples I found deal with the rather simple task of just comparing one property of a given database entity with a single parameter. Like so:
Session.Query.Where(m => m.Name.Contains("test"))
还可以通过以下更通用的方法来实现:
Which could also be achieved with a far more generic approach like this:
var item = Expression.Parameter(typeof (MyClass), "item");
var property = Expression.Property(item, "Name");
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var searchExpression = Expression.Constant(searchString, typeof(string));
var containsMethodExpression = Expression.Call(property, containsMethod, searchExpression);
var lambda = Expression.Lambda<Func<MyClass, bool>>(containsMethodExpression, item);
query = query.Where(lambda);
但是,有时任务要复杂一些,而人们想要实现以下目标:
However, sometimes the task is somewhat more complex and one wants to attain something like the following:
Session.Query.Where(m => m.SpecialProperty.Any(f => f.Name.Contains("test")));
其中"SpecialProperty"的类型为List<>,而属性"Name"的类型为string.
Where "SpecialProperty" is of the type List<> and the property "Name" is of the type string.
是否可以动态构建这样的Linq表达式,如何实现?这种方法是否存在性能方面的问题?
Is it possible to build a Linq expression like this dynamically and how could this be achieved? Are there any performance concerns regarding this approach?
推荐答案
找到了一种在我的特定用例中可以正常工作并且可以完成我所寻找的解决方案.
Found a solution that is working in my particular use case and does exactly what I was looking for.
/*
building expression tree
example: Session.Query.Where(m => m.SpecialProperty.Any(f => f.Name.Contains("test")))
*/
var innerItem = Expression.Parameter(typeof(MyInnerClass), "f");
var innerProperty = Expression.Property(innerItem, "Name");
var innerMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var innerSearchExpression = Expression.Constant(searchString, typeof(string));
var innerMethodExpression = Expression.Call(innerProperty, innerMethod, new[] { innerSearchExpression });
var innerLambda = Expression.Lambda<Func<MyInnerClass, bool>>(innerMethodExpression, innerItem);
var outerItem = Expression.Parameter(typeof(MyOuterClass), "m");
var outerProperty = Expression.Property(outerItem, info.Name);
/* calling a method extension defined in Enumerable */
var outerMethodExpression = Expression.Call(typeof(Enumerable), "Any", new[] { typeof(MyInnerClass) }, outerProperty, innerLambda);
var outerLambda = Expression.Lambda<Func<MyOuterClass, bool>>(outerMethodExpression, outerItem);
query = query.Where(outerLambda);
需要这种相当陈旧的方法,而不是更优雅的单行LINQ-Expression,以允许类型和方法名称的参数化. 但是,我当然不会介意关于可能的性能损失的其他建议和想法.
This rather dowdy approach is needed instead of the more elegant single line LINQ-Expression to allow for parametrization of types and method names. However, I of course wouldn't mind other suggestions and ideas on possible performance penalties.
It is very likely that this code snippet could also assist in solving How to produce a Subquery using non-generic Lambda.
这篇关于动态创建包含子查询的Linq表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!