当 LINQ 查询的条件为 null 时,如何防止出现多个结果?

How do I prevent multiple results when condition is null for a LINQ query?

假设以下两个SQL表。

db.Fruits

ID  Name
F1  Apple
F2  Orange
F3  Melon

db.Attributes

ID  Fruits_ID   AttributeType   AttributeValue
A1  F1          Color           Red
A2  F3          Size            Large
A3  F2          Size            Small
A4  F1          Size            Small
A6  F3          Color           Brown

如何使用 LINQ 查询在多个可为 null 的条件下搜索我想要的水果,而不用通过 JOIN 将结果相乘?例如,如果 condition 为空,则以下查询会生成多个结果。

var q = from f in db.Fruits
        join a in db.Attributes
        on f.ID equals a.Fruits_ID
        where string.IsNullOrEmpty(condition) || fa.AttributeValue.Contains(conditon)
        select FruitResult
        {
            // ...
        }

无论如何,我也调查过 INTO 但这对我不起作用。

var q = from f in db.Fruits
        join a in db.Attributes
        on f.ID equals a.Fruits_ID
        into FruitsAttributes

        from fa in FruitsAttributes
        where string.IsNullOrEmpty(condition) || fa.AttributeValue.Contains(conditon)
        select FruitResult
        {
            // ...
        }

condition 为 null 或为空时,上述仍然是 returns multiple/joined 结果。

TL;DR: 如何使用一对多 .Contains 检查我的查询,如果条件为空,returns 个人 "unjoined" 行?

您可以试试这个查询:

var q = from f in db.Fruits
                join a in db.Attributes
                on f.Id equals a.FruitId
                into g
                select new FruitResult
                {
                    Id = f.Id,
                    Name = f.Name,
                    Attribute = condition != null ? g.FirstOrDefault(a => a.AttributeValue.Contains(condition)) : null
                };

你可以很容易地在select中扩展检索属性值,我不知道你需要什么,所以我保持原样。

如果 condition 为 null,我猜你期待一个空集,因为它不匹配任何属性?最简单的方法是单独处理这种情况。

IEnumerable<FruitResult> q;
if (!string.IsNullOrEmpty(condition))
{
    q = from f in db.Fruits
        join a in db.Attributes
        on f.ID equals a.Fruits_ID
        where fa.AttributeValue.Contains(conditon)
        select FruitResult
        {
            // ...
        }
}
else
{
    q = Enumberable.Empty<FruitResult>();
}

终于有了答案。其实很简单,只需要创建一个过滤器并跳过连接即可。

var qFilter = from a in db.Attributes
              where a.AttributeValue.Contains(condition)
              select a.Fruits_ID

var q = from f in db.Fruits
        where string.IsNullOrEmpty(condition) || qFilter.Contains(f.ID)
        select FruitResult
        {
            // ...
        }