【问题标题】:LINQ query that searches for tuples搜索元组的 LINQ 查询
【发布时间】:2017-12-16 15:19:49
【问题描述】:

我有一个 FnameVersion 的元组 (List<Tuple<string,string>>) 列表作为输入。

例如。

[('firstname1','1.0.1'), ('firstname2','2.3.3'), ('firstname3','4.4.1')] 

是否可以编写一个 LINQ 查询,该查询基本上执行以下 SQL 查询的操作并返回 NameAttribX 的元组?

SELECT e.Name, a.AttribX
FROM Element e
JOIN Attributes a ON a.AId=e.EAId
where (a.FName='firstname1' and a.Version='1.0.1')
   OR (a.Fname='firstname2' and a.Version='2.3.3')
   OR (a.Fname='firstname3' and a.Version='4.4.1')

输入中有大约 1000 个元组。

【问题讨论】:

  • 101 Linq 示例页面是一个很好的起点。 Linq 支持加入两个列表,所以有一些示例:code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
  • 您想将元组用作实际 SQL Linq 查询的过滤器吗?
  • 是的,这是实体框架
  • 使用 1000 个元组,你正在构建一个地狱般的 SQL 查询,你确定没有其他选择吗?
  • @Chris 你已经建议了,现在这意味着有人会在答案中使用它并获得支持!

标签: c# linq


【解决方案1】:

如果您正在生成 SQL,则可以通过稍微显式地构建 where 子句来避免字符串连接:

Expression<Func<Attributes, bool>> inTuples = a => false;
inTuples = yourListOfTuples.Aggregate(inTuples, (predicate, tuple) => predicate
    .Or(a => a.FName == tuple.Item1 && a.Version == tuple.Item2));

上面 sn-p 中的Or 是一个用于组合两个表达式的简单实用程序。有关代码,请参见 this answer,以及对应的 And。这两种扩展方法在处理表达式时非常有用。

您现在可以使用此inTuples 表达式来过滤Attributes 的查询,生成的where 子句将匹配所需的形式:

var filteredQuery = attributesQuery.Where(inTuples).AsEnumerable();

您可能需要做一些修改才能将结果转换为元组列表:

var resultingTuples = filteredQuery
    .Select(a => new {a.Name, a.AttribX})
    .AsEnumerable()
    .Select(a => (a.FName, a.AttribX))
    .ToList();

(请注意,我返回 a.FName 而不是 e.Name 以保持示例简单。)

【讨论】:

  • 我在...(inTuples, (predicate, tuple) =&gt; predicate.OR... 中遇到错误...(inTuples, (predicate, tuple) =&gt; predicate.OR... 有什么想法吗?
  • 啊,从stackoverflow.com/questions/1266742/… 找到答案我需要为 OR 构建一个函数扩展,如链接中所述。
  • 感谢您的回复。我的回答更清楚了。
  • 它编译得很好,但是当我尝试运行它时,我在 Or 语句中收到错误 The binary operator Or is not defined for the types 'System.Func'2[MainDB.tblOrder,System.Boolean]' and 'System.Func'2[MainDB.tblOrder,System.Boolean]'."}。我最终使用了从 stackoverflow.com/questions/6912733/… 获得的 PredicateBuilder。这与您的答案非常相似。我喜欢你的回答,但不知道为什么它不起作用:(
【解决方案2】:

您的 Where 子句可能是(如果使用 LINQ to Objects):

var results = yourData.Where(z => yourListOfTuples.Contains(new Tuple<string, string>(z.FirstName, z.Version)))

另一个尝试的选项(针对实体框架):

var tuples = yourListOfTuples.Select(z => z.Item1 + "-" + z.Item2).ToList();
var results = yourData.Where(z => tuples.Contains(z.FirstName + "-" + z.Version))

第二个代码示例只是连接两个字段 - 这将对数据库查找产生负面影响(因为它可能必须进行扫描而不是查找)。例如,如果FirstNameLastName 包含-,您也可能会遇到问题。从好的方面来说,它将只使用 1000 个参数而不是 2000 个。:)

【讨论】:

  • 如果源是实体框架数据库集,这将不起作用。
  • 好点@DavidG!如果源数据(即yourData)是实体框架等,那么这将不起作用。见stackoverflow.com/questions/17595105/…
  • @DavidG OP 明确表示他/她有一个元组列表
  • @Esko 是的,作为输入,但没有明确说明来源是什么。我怀疑元组实际上是 DbSet 查询的过滤器。比如AttribX从哪里来?
  • 然后考虑将它们添加到数据库中并完全避免使用元组。它们很少有好的用例(除了较新的 C#7 版本)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多