是否可以执行LINQ where子句并将a上的varchar字段拆分为一个集合,并将其与另一个集合进行比较,以查看是否有任何值匹配。
例如,我们有一个名为AllowedHolders的List<string>
,其中包含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)
任何想法都会非常感激。如果您需要我进一步解释,请告诉我。
安迪
答案 0 :(得分: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()
调用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);
答案 1 :(得分: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)
);
正如第一条评论所指出的,如果没有持有者名称包含另一个持有者名称作为子字符串,则此仅有效。我隐含地假设您的所有持有人姓名都是三个字母的字符串,如ARR
和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)
);
答案 2 :(得分: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 %%并不快。