【问题标题】:Conditional Where clause in LINQLINQ 中的条件 Where 子句
【发布时间】:2015-04-02 21:19:06
【问题描述】:

假设我在网格中显示数据,并且我有许多文本框用于过滤数据。 员工 ID 的文本框。如果员工 ID 文本框为空,则不会添加 where 子句,但如果它不为空,则将为此添加 where 子句。如果薪水文本框有值或员工姓名文本框有值,我们可以过滤数据。

我尝试编写条件 LINQ 查询但出错。这是我的

var sName="";

var r = from t in TblFamilies
where 1 == 1
if(sName!="")
{
  && t.Name="Keith";
};

select new
{
    t.ID,
    t.ParentID,
    t.Name,
    t.CurDate
};

r.Dump();               

【问题讨论】:

  • 你遇到了什么错误?
  • 动态查询就是你想要的。
  • 我在 linq pad 中测试 linq。
  • 您可以在查询后轻松链接多个.Where() 函数。您不需要创建“条件位置”。即使在 SQL 中,“条件 where”也是不好的做法,因为它会导致执行计划效率低下
  • 如果用户输入 Jim,您确定要搜索 Keith?

标签: c# linq


【解决方案1】:

试试这个:-

首先选择数据:-

var r = from t in TblFamilie
select new
{
    t.ID,
    t.ParentID,
    t.Name,
    t.CurDate
};

然后就可以根据条件过滤了:-

   if (sName!="")
        r = r.Where(x => x.Name == sName);

【讨论】:

  • 不需要1==1
  • @RahulSingh:谢谢。有效。您添加过滤器 linq 的方式将生成 AND 关键字而不是 OR。那我怎么能让它动态化。假设我会说 linq 将使用什么运算符来生成 sql,例如 And , OR
  • @Mou - 您可以在 Where 子句本身中使用 || 运算符:- `r.Where(x => x.Name == sName || x.Name = "Test")'例如。
  • 查看我的 sql where Name='Keith' OR ID=2。我不想总是使用像Name='Keith' AND ID=2 这样的 AND 运算符
  • @Mou - 我就是这个意思,你可以写:if (id > 0) { r = r.Where(x => x.Name == "Keith" || x.ID == 2); }
【解决方案2】:

如果您想将And 运算符和Or 运算符混合在一起,请在此处查看PredicateBuilderhttp://www.albahari.com/nutshell/predicatebuilder.aspx

你可以简单地写成:

// begin with true if you start with And operator.
var predicate = PredicateBuilder.True<TblFamilie>();
predicate = predicate.And(t => t.CureDate < DateTime.UtcNow.AddDays(-1));
// you can mix with Or operator too.
predicate = predicate.Or(t => t.Name.Contains("blah"));

var results = context.TblFamilie
.Where(predicate)
.Select(new
{
  // your projection here...
});


// begin with false if you start with Or operator.
var predicate2 = PredicateBuilder.False<TblFamilie>();
predicate2 = predicate2.Or(t => t.CureDate < DateTime.UtcNow.AddDays(-1));
// you can mix with And operator too.
predicate2 = predicate2.And(t => t.Name.Contains("blah"));

var results = context.TblFamilie
.Where(predicate)
.Select(new
{
  // your projection here...
});


// even nesting is possible
var inner = PredicateBuilder.False<TblFamilie>();
inner = inner.Or (p => p.Name.Contains("foo"));
inner = inner.Or (p => p.Name.Contains("bar"));

var outer = PredicateBuilder.True<TblFamilie>();
outer = outer.And (p => p.CureDate > DateTime.UtcNow.AddDays(-3));
outer = outer.And (p => p.CureDate < DateTime.UtcNow.AddDays(-1));
outer = outer.And (inner);

var results = context.TblFamilie
.Where(outer)
.Select(new
{
  // your projection here...
});

更新

好的,假设您有一个Family 课程,并且您从某个地方获得了“家庭”。你可以像这样使用PredicateBuilder

// you have 4 families from DB, API or anywhere.
var failies = new List<Family>
{
    new Family { Id = 1, ParentId = 1, Name = "foo", Birthday = new DateTime(1971, 1, 1) },
    new Family { Id = 1, ParentId = 1, Name = "bar", Birthday = new DateTime(1982, 1, 1) },
    new Family { Id = 1, ParentId = 1, Name = "foobar", Birthday = new DateTime(1993, 1, 1) },
    new Family { Id = 1, ParentId = 1, Name = "fake", Birthday = new DateTime(2000, 1, 1) },
};

// make predicate!
// if a family's Birthday is before than 1980 'or' Name contains "ke".
var predicate = PredicateBuilder.True<Family>();
predicate = predicate.And(o => o.Birthday < new DateTime(1980, 1, 1));
predicate = predicate.Or(o => o.Name.Contains("ke"));

// you should make IQueryable in order to use PredicateBuilder.
var result = failies.AsQueryable()
    .Where(predicate)
    .Select(o => new
    {
        o.Id, o.Name, o.Birthday    // only project what you want.
    })
    .ToList();

// now, result should contains "foo" and "fake".
foreach (var family in result)
{
    Debug.WriteLine("Name: " + family.Name);
}

更新2

您可以复制并粘贴到 LinqPad 以测试它的工作原理。在 LinqPad 中运行之前,

  • 从以上链接下载LinqKit.dll
  • 确保按“F4”> 添加 > 浏览 > 选择 LinqKit.dll > 在“其他命名空间导入”选项卡中添加 LinqKit 命名空间。
  • 在“查询”面板中,选择“C# 语句”的语言

粘贴并运行。

// you have 4 strings from DB, API or anywhere.
var strings = new List<string>
{
    "foo",
    "bar",
    "foobar",
    "fake"
};


// make predicate!
// if a string contains "oo" or "ke"
var predicate = PredicateBuilder.True<string>();
predicate = predicate.And(o => o.Contains("oo"));
predicate = predicate.Or(o => o.Contains("ke"));

// you should make IQueryable in order to use PredicateBuilder.
var result = strings.AsQueryable()
    .Where(predicate)
    .ToList();

// now, result should contains "foo", "foobar" and "fake".
foreach (var stringResult in result)
{
    Debug.WriteLine("Name: " + stringResult);
}

【讨论】:

  • 对于 PredicateBuilder 是否需要添加任何程序集或任何不附带 dotnet 的类。
  • 是的,访问我发布的站点,您可以获取文章中的源代码。它只是一个只有几行代码的类。我不认为有任何限制困扰你。
  • 我在 LINQPad 中添加了 linqkit 并尝试执行您提供的查询,但出现错误 'LINQPad.User.TypedDataContext.TblFamilies' is a 'property' but is used like a 'type'
  • 以上代码只是一个示例,并不准确。在PredicateBuilder.True&lt;TblFamilie&gt; 中,您应该将TblFamile 更改为其实际的“类型”。而且我假设您正在使用某种 ORM,例如 EntityFramework 或其他东西。如果不是,请在源 IEnumerable 实例之后调用 .AsQueryable()。 PredicateBuilder 仅适用于 IQueryable
  • 我没有使用 EF,也无法理解如何再次使用谓词生成器我的表 TblFamilies 在 LINQ pad 中可以正常运行。你能用 PredicateBuilder 构造语句,它会成功运行吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-09
  • 1970-01-01
  • 2012-05-06
相关资源
最近更新 更多