0

是否可以执行 LINQ where 子句并将 : 上的 varchar 字段拆分为一个集合并将其与另一个集合进行比较以查看是否有任何值匹配。

例如,我们有一个List<string>名为 AllowedHolders,其中包含 ARR ACC 等。但是数据库中的字段(不幸的是我们无法更改)是一个 varchar,但具有用冒号分隔的值:即“:ARR:ACC:”

我们想做的是编写一个 LINQ where 子句,它可以检查字段中是否出现任何 AllowedHolders。因为我们希望将结果限制为仅带回字段包含 AllowedHolders 集合中的值的记录。

我们在字段仅包含单个值的情况下完成了以下操作

searchResults = searchResults.Where(S => searchParams.AllowedBusinessAreas.Contains(S.SIT_BusinessArea));

但以下内容将不起作用,因为 SIT_HolderNames 包含由冒号分隔的值:

searchResults = searchResults.Where(S => searchParams.AllowedHolders.Contains(S.SIT_HolderName)

任何想法将不胜感激。如果您需要我进一步解释,请告诉我。

安迪

4

3 回答 3

2

使用和。Intersect()_Any()String.Split()

searchResults = searchResults.Where(s => searchParams.AllowedHolders.Intersect(S.SIT_HolderName.Split(':')).Any());

例如:

":ACC:TEST::ARR:".Split(':') -> string[] { "", "ACC", "TEST", "", "ARR", "" };  

您可以注意到空字符串,如果您不想考虑使用 String.Split(char[], StringSplitOptions.RemoveEmptyEntries):

":ACC:TEST::ARR:".Split(new char[] {':'}, StringSplitOptions.RemoveEmptyEntries) -> string[] { "ACC", "TEST", "ARR" };

更新

String.Split()在调用using之前,您必须获取数据ToList()

searchResults = searchResults.ToList().Where(s => searchParams.AllowedHolders.Intersect(S.SIT_HolderName.Split(':')).Any());

如果里面的数据searchResults太大,你可以做的是只获取一个主键和SIT_HolderName.

var keys = searchResults.Select(s => new { Key = s.SIT_PKey, SIT_HolderName = s.SIT_HolderName })
                        .ToList()
                        .Where(s => searchParams.AllowedHolders.Intersect(s.SIT_HolderName.Split(':')).Any())
                        .Select(s => s.Key)
                        .ToList();

searchResult = searchResults.Where(s => keys.Contains(s.SIT_PKey));

我不知道上述查询的表现是什么。否则,您可以尝试使用Join()

searchResult = searchResults.Join(keys, s => s.SIT_PKey, key => key, (s, key) => s);
于 2013-01-30T11:53:03.313 回答
1

也许你可以使用:

searchResults = searchResults.Where(S => searchParams.AllowedHolders
  .Any(H => S.SIT_HolderName.Contains(H))
  );

或者

searchResults = searchResults.Where(S => searchParams.AllowedHolders
  .Any(S.SIT_HolderName.Contains)
  );

正如第一条评论所指出的,这在没有持有人姓名包含另一个持有人姓名作为子字符串的情况下才有效。我隐含地假设您的所有持有人姓名都是三字母字符串,例如ARRand ACC。如果不是这种情况,请考虑使用(":" + H + ":"),或找到更安全的解决方案。

编辑:为了完整起见,这里有两个带有冒号的版本:

// OK if some name is contained in another name as a substring
// Requires colon before the first and after the last name
searchResults = searchResults.Where(S => searchParams.AllowedHolders
  .Any(H => S.SIT_HolderName.Contains(":" + H + ":"))
  );

和:

// OK if some name is contained in another name as a substring
// Ugly checks included to handle cases where no colons are present in the extreme ends
searchResults = searchResults.Where(S => searchParams.AllowedHolders
  .Any(H => S.SIT_HolderName.Contains(":" + H + ":") || S.SIT_HolderName.StartsWith(H + ":") || S.SIT_HolderName.EndsWith(":" + H) || S.SIT_HolderName == H)
  );
于 2013-01-30T12:15:45.657 回答
0

如果在 DB 列的值中,分隔符确实采用以下格式:

:AAA:BBB:CCC:DDD:

而不仅仅是(请注意第一个和最后一个字符!)

AAA:BBB:CCC:DDD

那么您可以执行LIKE查找:

select .... from ... where column LIKE '%:BBB:%'

转化为 LINQ:

var idWithColons = ":" + "BBB" + ":";

from ... where .... column.Contains(idWithColons)

对于许多可能的 IDS,您必须生成:

select .... from ... where column LIKE '%:BBB:%' OR column LIKE '%:DDD:%' OR ..

转化为 LINQ:

var idWithColons = ":" + "BBB" + ":";
var idWithColons2 = ":" + "DDD" + ":";

from ... where .... column.Contains(idWithColons) or column.Contains(idWithColons2)

但这仅适用于少数替代品。对于未知的 ID 列表,您可以尝试将其重写为动态构建的过滤器,但如果您不熟悉这并不容易Expression<Func<>>.. 无论如何,通过 LIKE 搜索无论如何都不是一个好主意.. 但这不是很多其他选择:/

否则,好吧,那很不漂亮..您可能会在 sql 服务器上准备一个标量值函数并以某种方式在您的 linq 提供程序中注册它,但我认为这不值得..

编辑:

解释动态构建 where 子句,即。在这里http://www.albahari.com/nutshell/predicatebuilder.aspx - 寻找 PredicateBuilder。构建器实际上是通用的,可以直接使用,但您仍然必须自己编写连接 OR-LIKE 的小循环。我认为这篇文章写得很好,如果您发现任何问题,请给我留言。除了表演。LIKE %% 并不快。

于 2013-01-30T11:57:16.643 回答