【问题标题】:Dynamic LINQ on a collection?集合上的动态 LINQ?
【发布时间】:2009-08-20 13:05:22
【问题描述】:

我有一个项目要求我做一个这么大的搜索引擎,但它是动态的。我的意思是我可以有大约 0 到 9 个主要的“组”,其中包含无限的可能性,比如用“OR”或“AND”来“在哪里”。我们首先想到的是使用 Dynamic Linq,它为构建动态查询提供了一个很好的替代方案。所有这些都使用带有自制包装器的 EF。

问题: 我无法访问“收藏”。我的意思是,我可以轻松访问引用的对象(例如 Customer.State.StateName = "New-York" OR Custoemr.State.StateName = "Quebec" )但我找不到方法访问类似:“Customer.Orders.OrderID = 2 OR Customer.Orders.OrderID = 3”。我可以很容易地弄清楚这是因为它是一个集合,但是我该怎么做呢?

请帮帮我!!

** 对不起我的英语!!


更新

我觉得我不太清楚,对不起,因为我是法国人......

我的问题是因为没有什么是静态的。它是招聘公司的候选人搜索引擎,可将候选人放入企业。在经理可以搜索候选人的页面中,他可以通过以下方式“解析”:域(工作)、城市或许多其他用户在注册时填写的内容。所有这些都是格式(如果它是在 SQL 中):

[...] WHERE (domaine.domainID = 3 OR domaine.domainID = 5 OR domaine.domainID = 23) AND (cities.cityID = 4, cities.city = 32) [...]

所以我不能用普通的 LINQ 格式来做到这一点:

Candidat.Domaines.Where(domain => domain.DomainID == 3 || domain.DomainID == 5 || domain.DomainID == 23);

即使是括号中的运算符也是动态的(“AND”或“OR”)!这就是我们尝试使用 Dynamic Linq 的原因,因为它更加灵活。

希望它更容易理解我的问题...


更新 2 这是我的方法

private string BuildDomainsWhereClause() {
        StringBuilder theWhere = new StringBuilder();

        if (this.Domaines.NumberOfIDs > 0) {
            theWhere.Append("( ");

            theWhere.Append(string.Format("Domaines.Where( "));
            foreach (int i in this.Domaines.ListOfIDs) {
                if (this.Domaines.ListOfIDs.IndexOf(i) > 0) {
                    theWhere.Append(string.Format(" {0} ", this.DispoJours.AndOr == AndOrEnum.And ? "&&" : "||"));
                }
                theWhere.Append(string.Format("DomaineId == {0}", i));
            }
            theWhere.Append(" ))");
        }

        return theWhere.ToString();
    }

它“不返回布尔值”反而效果很好。那我该怎么办? 错误:“预期为 'Boolean' 类型的表达式”。

最后,它返回如下内容:“( Domaines.Where( DomaineId == 2 && DomaineId == 3 && DomaineId == 4 && DomaineId == 5 ))。”添加到我的 LINQ 查询中:

var queryWithWhere = from c in m_context.Candidats.Where(WHERE)
                                     select c;

不要忘记还有 7 或 8 个“可能”添加的内容要搜索...有什么想法吗?

【问题讨论】:

    标签: c# asp.net entity-framework dynamic-linq


    【解决方案1】:

    您需要在这里做的是构建一个LambdaExpression(更具体地说是一个Expression<Func<T, bool>>)。您不能使用字符串。您可以像这样构建一个简单的表达式:

    ParameterExpression p = Expression.Parameter(typeof(Domaine), "domaine");
    Expression<Func<Domaine, bool>> wherePredicate = 
      Expression.Lambda<Func<Domaine, bool>>(
        Expression.Or(
          Expression.Equal(
            Expression.Property(p, "DomainID"),
            Expression.Constant(10)),
          Expression.Equal(
            Expression.Property(p, "DomainID"),
            Expression.Constant(11))
          ), p);
    

    即,

    domaine.DomainID = 10 || domaine.DomainID = 11

    如果您需要手动执行此操作,则可读性较差。

    在 MSDN 代码库的 DynamicQuery 下,有一个完全可操作的表达式解析器示例,它实际上会根据 C# Samples for Visual Studio 2008 中的字符串为您执行此操作。 (LinqDataSource 控件在内部使用了此示例的略微修改版本。)

    【讨论】:

    • 非常感谢。它不完全是我所期望的,但它看起来很棒。我仍然需要对其进行一些技巧以使其完美动态。不过谢谢,非常有用。
    【解决方案2】:

    我终于如愿以偿了。

    private string BuildDomainsWhereClause() {
            StringBuilder theWhere = new StringBuilder();
    
            if (this.Domains.NumberOfIDs > 0) {
                theWhere.Append("( ");
    
                foreach (int i in this.Domains.ListOfIDs) {
                    if (this.Domains.ListOfIDs.IndexOf(i) > 0) {
                        theWhere.Append(string.Format(" {0} ", this.Domains.AndOr == AndOrEnum.And ? "&&" : "||"));
                    }
                    theWhere.Append(string.Format("Domains.Any(IdDomaine== {0})", i));
                }
                theWhere.Append(" )");
            }
    
            return theWhere.ToString();
        }
    

    这会产生类似:“(DispoJours.Any(IdDispo == 3) && DispoJours.Any(IdDispo == 5))”。

    我所有的其他“Where builder”都将使用“&&”来执行相同的操作,它们之间会给出正确的结果。

    后来:

    var queryWithWhere = from c in m_context.Candidats.Where(WHERE)
                         select c;
    

    呜呜呜!!谢谢各位。非常有用!喜欢这个网站!


    更新

    别忘了我在这个查询中使用了 Dynamic Linq。这不是普通的 LINQ 查询。

    【讨论】:

    • 如果您要使用字符串构建实际查询,请确保对字符串进行参数化,否则您可能容易受到 SQL 注入攻击。虽然它可能是更简单的方法,但有时它不一定是最好/最安全的方法。如果您使用 LINQ 进行查询,它会自动为您参数化查询。
    • 非常感谢阻止我。现在我们不再使用 SQL,我已经忘记了那些危险的事情。谢谢。但在我的情况下,用户不写“1”,他在复选框列表中选择它,所以危险并不存在。无论如何我都会这样做,但并没有真正的危险。
    【解决方案3】:

    假设 Customer.Orders 返回一个集合,这正是您不能只调用它的属性的原因。

    为了使用 LINQ 获取您要查找的订单,您需要知道 OrderID(或其他一些属性),在这种情况下您可以这样做:

    Customer.Orders.Find(order => order.OrderID == 2);
    

    编辑:以这种方式添加表达式以查找 id 2 或 3:

    Customer.Orders.FindAll(order => order.OrderID == 2 || order.OrderID == 3);
    

    【讨论】:

      【解决方案4】:

      我是否理解正确,Customers 是一个集合,Orders 是一个集合,而 State(显然)是一个 Property?

      var q = from a in Customer
          from b in a.Orders
          where b.ID == 2
                    || b.ID == 3
          select b;
      

      我猜会起作用的。

      编辑

      我做了部分类似的事情。太长时间无法确定我是如何做到的,但我可以告诉你,我正在使用

      public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values);
      

      来自 DynamicQueryable 类。

      this.CountrySitesObject.Sites.AsQueryable().Where(w.WhereQuery, w.WhereParameters) 
      

      (从我的代码中复制)。

      【讨论】:

      • 是的,效果很好。但是,当您真的不知道必须搜索多少个“b.Id”时,情况并非如此。即使不是“||”或“&&”之间。
      • 我也会试试这个。但我在一个似乎有效的解决方案上。我稍后会回来告诉你消息。
      【解决方案5】:

      如果你退后一步,问客户想做什么。

      Filter bug information.
      

      为什么不将数据导出到 excel 或将 excel 指向 SQL 表。构建起来没有那么有趣,但你会在几个小时内完成,而不是几天或几周。 :)

      【讨论】:

      • 是的,我知道!但我们认为 Dynamic LINQ 所做的正是我们正在寻找的......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-11
      相关资源
      最近更新 更多