动态生成 LINQ 查询

Posted

技术标签:

【中文标题】动态生成 LINQ 查询【英文标题】:Dynamically generate LINQ queries 【发布时间】:2012-02-29 19:13:45 【问题描述】:

我们有一个对象

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'

这个可以吗?

【问题讨论】:

有几种不同的方法可以做到这一点。它是否永远是属性 == 价值。小于、大于、不等于可能吗? XML 可以指定多个值吗? Name = 'Bob' || Name = 'Fred'。条件是否仅与 && 结合? Name = 'Bob' && State = 'OH'。或者条件可以与||结合吗? Name = 'Bob' || State = 'OH'。在提出解决方案之前,所有这些都需要考虑在内。 问题不够清晰;它并没有表明 XML 结构将包含条件表达式(而不仅仅是要匹配的所需值,正如 Name = 'Bob' 似乎暗示的那样)。有人发现适合对所有未推断出此缺失信息的答案投反对票,这是愚蠢和无益的。 @Cadrell0 - 更复杂的查询将是一个很好的补充。我试图从一个简单的 where 子句开始这个问题。我不知道这本身是否是一个非常复杂的解决方案。从答案来看,似乎有一个完整的库可以用来完成这些任务。 ScottGU 的动态 LINQ 看起来很有前景。 你应该试试 Gridify 库:github.com/alirezanet/Gridify 【参考方案1】:

这是一个带有表达式树的解决方案:

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 因为虽然表达式树一开始可能有点难以理解,但它们是解决这个问题的好方法。一旦您通过了那里的初始示例,请注意处理空值并确保表达式中使用的类型彼此匹配。根据查询源的“动态”程度(例如,所有 Expression.Constants() 都以字符串形式出现,即使它们与 int 进行比较),您可能需要进行一些额外的转换。这篇 MSDN 文章也是一个很好的参考 - msdn.microsoft.com/en-us/library/bb882637.aspx 我爱你,伙计。你用两行代码简化了这个混乱。让我指出 someObj 必须是 IQueryable 才能接受 Where(exp) 如果您想在相等的 Linq 查询中使用动态列名(在本例中为“NAME”),此解决方案也很好。 确实有帮助但是使用LinqKit库更快github.com/scottksmith95/LINQKit 真希望我们能以这种方式构建查询语法(不是 Lambda 语法)...【参考方案2】:

根据您的问题我很难判断,但在某些情况下您不需要动态 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;

当相关参数为空时,这将从本质上防止数据被过滤。由于 C# 中的短路行为,它仍然表现良好。

【讨论】:

你的想法让我在不使用复杂的动态 Linq 库的情况下解决了我的问题。以原生方式解决它。谢谢 这对我来说效果很好。我忘记了我们曾经在 SQL 存储过程中这样做,所以很容易看出为什么它会在 Linq 中工作。【参考方案3】:

您肯定想看看Dynamic Linq,它允许您将查询条件定义为文本。

至于动态添加条件,您可以使用类似的语法向查询添加条件;

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

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

【讨论】:

Where("SomeText") 是的。你确定了我想要实现的概念。 这是一篇较旧的帖子,因此可能与此特定问题无关,但 Dynamic Linq 不是框架的内置功能。它作为源代码发布,您可以下载并编译到您的应用程序中 (github.com/kahanu/System.Linq.Dynamic)。根据您的应用,这可能不合适,所以只是想提高一些对此的认识。【参考方案4】:

我相信您将不得不深入研究Expression Trees。我对此没有深入研究,因此无法为您创建示例,但我知道您可以使用表达式树来动态构建查询,然后调用 .Compile(在代码中)使其可运行。

其实这里有一个更好的链接Building Dynamic Queries with Expression Trees。它应该给你你想要的,并且相当简洁。这对你来说应该是一个很好的例子:)

【讨论】:

Antineutrino 的答案可能是最简单的,您可以在其中传入字符串。但是,我相信 Expression Tree 中的 .compile 方法可以为您提供类型检查,因此在这个意义上它更安全一些。但是,据我所知,实现表达式树并非易事。 为什么这被否决了?它似乎绝对适合这个问题,所以我会很感激拒绝投票的理由? 表达树 - 适合全家人一起玩 :) 投票赞成,因为其他解决方案都没有提到它们。【参考方案5】:

也许 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);

【讨论】:

是的,但是你能粘贴一个示例代码来展示使用动态 linq 是如何工作的吗? 您可以在 where 子句中使用字符串,例如query = query.Where("Id=123 And Age> 18"); 我的话,伙计,我需要为你做编辑吗?编辑您的帖子并包含该信息。那就来点赞吧。然后进行游戏化。【参考方案6】:

我假设您想要引入可选过滤器,具体取决于您的 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 中实际指定的内容。

【讨论】:

【参考方案7】:

是的,其实很简单:

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));

基本上,您可以在这些方面做很多事情。如果您想要更具体地适合您的情况的答案,您需要提供更具体的问题。

【讨论】:

不,你错过了他的问题。如何从文本字段创建 linq 查询? @jcolebrand:您能否阐明“从文本字段创建 linq 查询”的意思?据我所知,考虑到问题的模糊性,我已经尽可能地回答了这个问题。

以上是关于动态生成 LINQ 查询的主要内容,如果未能解决你的问题,请参考以下文章

c# linq 动态多条件查询语句的写法

使用 C# 和 Linq 动态生成 kml 文件 [重复]

Linq To Sql进阶系列用object的动态查询与保存log篇

关于动态生成SQL语句的简单实现

动态创建生成lambd表达式

TSQL - 从记录集中动态生成查询