Linq:有条件地向where子句添加条件


102

我有这样的查询

(from u in DataContext.Users
       where u.Division == strUserDiv 
       && u.Age > 18
       && u.Height > strHeightinFeet  
       select new DTO_UserMaster
       {
         Prop1 = u.Name,
       }).ToList();

我想根据是否向运行此查询的方法提供了这些条件来添加年龄,身高等各种条件。所有条件都将包括用户部门。如果提供了年龄,我想将其添加到查询中。同样,如果提供了高度,我也想添加。

如果要使用sql查询完成此操作,我将使用字符串生成器将其附加到主strSQL查询中。但是在Linq中,我只能想到使用IF条件,在该条件下我将写入相同的查询三次,而每个IF块都有一个附加条件。有一个更好的方法吗?

Answers:


182

如果您不调用,ToList()并且最终映射到DTO类型,则可以随时添加Where子句,并在最后构建结果:

var query = from u in DataContext.Users
   where u.Division == strUserDiv 
   && u.Age > 18
   && u.Height > strHeightinFeet
   select u;

if (useAge)
   query = query.Where(u => u.Age > age);

if (useHeight)
   query = query.Where(u => u.Height > strHeightinFeet);

// Build the results at the end
var results = query.Select(u => new DTO_UserMaster
   {
     Prop1 = u.Name,
   }).ToList();

这仍然只会导致对数据库的单次调用,其效果将与一次编写查询一样有效。


1
我是否需要将所有where条件放在“ var query = ..”语句中?
user20358 2012年

4
随后的条件汇总为“或”或“与”吗?
Vi100

4
@ vi100,它们将成为其他过滤器,因此AND
Reed Copsey

谢天谢地,简单!当上面的内容更具可读性时,我非常讨厌看到20条以上的Linq查询
justanotherdev

为什么我收到此错误LINQ to Entities does not recognize the method 'System.String get_Item(System.String)' method, and this method cannot be translated into a store expression.
Ali Umair

18

我通常使用方法链接,但是有相同的问题。这是我使用的扩展名

public static IQueryable<T> ConditionalWhere<T>(
        this IQueryable<T> source, 
        Func<bool> condition,
        Expression<Func<T, bool>> predicate)
    {
        if (condition())
        {
            return source.Where(predicate);
        }

        return source;
    }

它有助于避免链断裂。也一样ConditionalOrderByConditionalOrderByDescending是有帮助的。


有用,但是请您举例说明它的使用情况。
Suncat2000

1
它应该像这样:varfruits = await db.Fruits .ConditionalWhere(()=> color!= null,f => f.Color == color).ConditionalWhere(()=> mature!= null,f => f .Ripe ==成熟).ToListAsync();
Yuriy Granovskiy

4
很棒!谢谢!我还对条件作了重载,将其作为简单的布尔值而不是函数,以使其在代理将增加不必要的复杂性的地方更加直观。我现在经常使用这种扩展方法,非常感谢您的解决方案。
Suncat2000 '17

17

一种选择。

bool? age = null

(from u in DataContext.Users
           where u.Division == strUserDiv 
           && (age == null || (age != null && u.Age > age.Value))
           && u.Height > strHeightinFeet  
           select new DTO_UserMaster
           {
             Prop1 = u.Name,
           }).ToList();

或者您可以切换到linq的方法语法,并使用if条件将表达式附加到where子句。


3

我只是在我的where子句中使用它

    public IList<ent_para> getList(ent_para para){
     db.table1.Where(w=>(para.abc!=""?w.para==para.abc:true==true) && (para.xyz!=""?w.xyz==para.xyz:true==true)).ToList();
}

3

根据某些条件添加where条件...

from u in DataContext.Users
where u.Division == strUserDiv 
&& u.Age != null ? u.Age > 18 : 1== 1
&& u.Height != null ? u.Height > 18 : 1== 1
&& u.Height != null ? u.Height > 18 : 1== 1
 select new DTO_UserMaster
       {
         Prop1 = u.Name,
       }).ToList();

2

这是我做类似事情的代码。这是WCF SOAP Web服务api上的一种方法。

    public FruitListResponse GetFruits(string color, bool? ripe)
    {
        try
        {
            FruitContext db = new FruitContext();
            var query = db.Fruits.Select(f => f);
            if (color != null)
            {
                query = query.Where(f => f.Color == color);
            }
            if (ripe != null)
            {
                query = query.Where(f => f.Ripe == ripe);
            }
            return new FruitListResponse
            {
                Result = query.Select(f => new Fruit { Id = f.FruitId, Name = f.Name }).ToList()
            };
        }
        catch (Exception e)
        {
            return new FruitListResponse { ErrorMessage = e.Message };
        }
    }

基本查询Select(f => f)意味着基本上所有内容,并且Where子句可以选择附加到该查询。最后Select是可选的。我用来将数据库行对象转换为结果“水果”对象。


0

假设以下参数,

Int? Age = 18;

简单地使用&&||条件运算符,我们可以有另一个版本。

(from u in DataContext.Users
where u.Division == strUserDiv 
    && (Age == null || u.Age > Age)
    && (Param1 == null || u.param1 == Param1)
    && u.Height > strHeightinFeet
select new DTO_UserMaster
{
    Prop1 = u.Name,
}).ToList();

像Param1一样,您可以添加任意数量的搜索条件参数。


0

我只是偶然发现了这个东西,但以为我会使用lambda版本。

首先,我将创建一个类似这样的类以将参数传递到数据层:

   public class SearchParameters() {
       public int? Age {get; set;}
       public string Division {get;set;}
       etc
    }

然后,在我的数据层中,如下所示:

public IQueryable<User> SearchUsers(SearchParameters params) 
{
    var query = Context.Users;
    if (params.Age.HasValue)
    {
         query = query.Where(u => u.Age == params.Age.Value);
    }
    if (!string.IsNullOrEmpty(params.Division)
    {
        query = query.Where(u => u.Division == params.Division);
    }
    etc
    return query;
}

具体查询由您自己决定。在应用程序和数据之间可能会有一层,可以将特定于数据库的表示形式转换为与数据库无关的(也许您查询多个数据源)。例如,该层可能会从这些来源获取多种类型的可查询对象,并将它们映射到公共POCO表示形式。


糟糕,我没有看到约翰·亨克尔的答案。相同的想法。
斯科特·彼得森

0

仅在此处添加上述接受的答案,如果您要对联接进行动态搜索,请考虑在初始linq查询中返回包含两个表(t1,t2)的新对象,以便您可以单独访问它们以执行条件搜索。

var query = from t1 in _context.Table1
            join t2 in _context.Table2 on t1.Table1Id equals t2.Table1IdId
            select new { t1, t2 };

        if (!string.IsNullOrEmpty(searchProperty1))
        {
            query = query.Where(collection => collection.t1.TableColumn == searchProperty1);
        }
        if (!string.IsNullOrEmpty(searchProperty2))
        {
            query = query.Where(collection => collection.t2.TableColumn == searchProperty2);
        }
        ....etc.

我得到了我在这里寻找有关连接两个表并查询其中一个表中的特定列的答案

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.