动态生成LINQ查询

时间:2012-02-29 19:13:45

标签: c# xml linq

我们有一个对象

public class SomeObject
{
   public Name {get;set;}
   public City {get;set;}
   public State {get;set}
   //various other parameters.  Let's say there's ~20
}

是否可以在不重新编译源代码的情况下动态创建新的LINQ查询?相反,查询参数来自在数据库中存储和更新的XML结构。

var result = from i in someObj
             where 
             //XML requests Name = 'Bob'...so append this where clause
             name = 'Bob'

可以这样做吗?

7 个答案:

答案 0 :(得分:115)

以下是表达式树的解决方案:

var param = Expression.Parameter(typeof(SomeObject), "p");
var exp = Expression.Lambda<Func<SomeObject, bool>>(
    Expression.Equal(
        Expression.Property(param, "Name"),
        Expression.Constant("Bob")
    ),
    param
);
var query = someObj.Where(exp);

我知道它要复杂得多,但这可能会有用。

答案 1 :(得分:27)

您肯定希望查看Dynamic Linq,这样您就可以将查询条件定义为文本。

对于动态添加条件,您可以使用与<; p>类似的语法为查询添加条件

if(CategoryIsImportant)
    myQuery = myQuery.Where("CategoryId=2");

所有这些都可以(相当容易地)编码为您选择的XML格式。

答案 2 :(得分:26)

我很难根据您的问题来判断,但在某些情况下,您不需要动态Linq并且可以简单地执行此操作...

var result = from o in someObj 
             where (Name == null || o.Name == Name)
             && (City == null || o.City == City)
             && (State == null || o.State == State)
             select o;

这将基本上防止在有问题的参数为null时过滤数据。由于C#中的短路行为,它仍然表现良好。

答案 3 :(得分:9)

也许Dynamic Linq可以帮助您:Dynamic linq part 1: Using the linq dynamic query library

query = query.Where("Id = 123 And Age > 18");

或者您可以直接操作Linq查询:

query = query.Where(x=>x.Id == 5);

答案 4 :(得分:9)

我相信你必须真正深入研究Expression Trees。我没有深入挖掘这个,所以我不能为你创建一个样本,但我知道你可以使用表达式树来动态构建你的查询,然后调用.Compile(在代码中)让它可以运行。

实际上,这是一个更好的链接Building Dynamic Queries with Expression Trees。它应该给你你想要的东西,并且它是相当简洁的。这应该是一个很好的例子:)

答案 5 :(得分:5)

我假设您要引入可选过滤器,具体取决于XML的内容。要继续使用StriplingWarrior的示例:

var name = GetNameFromXml();
var city = GetCityFromXml();
var state = GetStateFromXml();

var result = someObj;
if (name != null)
    result = result.Where(i => i.Name == name);
if (city != null)
    result = result.Where(i => i.City == city);
if (state != null)
    result = result.Where(i => i.State == state);

这样,您将应用任意数量的过滤器(从无到三),具体取决于XML中实际指定的内容。

答案 6 :(得分:3)

是的,实际上非常简单:

var name = GetBobNameFromXml();
var result = someObj.Where(i => i.Name == name);

您还可以选择是否逐步应用标准。

var result = someObj;
var name = xmlCriteria.Name;
if(!string.IsNullOrEmpty(name))
{
    result = result.Where(i => i.Name == name);
}
// follow the same pattern for city, state, etc.

你甚至可以使用一个使用标准键的名称键控字典的模式来避免一堆if语句。

foreach(var criterionPair in xmlCriteria)
{
    var value = criterionPair.Value;
    result = result.Where(i => propGetters[criterionPair.PropertyName](i, value));
}

基本上,你可以沿着这些方向做很多事情。如果您想要根据您的具体情况量身定制答案,则需要提供更具体的问题。