我正在尝试使用LINQ for Entities(EF4 Code First)选择一些记录。
我有一个名为Monitoring的表,其中一个名为AnimalType的字段具有诸如
之类的值我想在字符串数组(animalValues)中传递一些值,并从Monitorings表中返回行,其中AnimalType字段中的一个或多个值与来自animalValues的一个或多个值匹配。以下代码ALMOST按照我的意愿工作,但我发现了我采用的方法存在一个重大缺陷。
public IQueryable<Monitoring> GetMonitoringList(string[] animalValues)
{
var result = from m in db.Monitorings
where animalValues.Any(c => m.AnimalType.Contains(c))
select m;
return result;
}
为了解释这个问题,如果我传入animalValues = {“Lion”,“Tiger”}我发现选择了三行,因为第4条记录“Mountain Lion”包含了“Lion”这个词作为一场比赛。
这不是我想要发生的事情。我需要“狮子”才能匹配“狮子”,而不是“山狮”。
另一个例子是,如果我传入“Snake”,我会得到包含“响尾蛇”的行。我希望有人能有更好的LINQ代码,它允许匹配精确逗号分隔值的匹配,而不仅仅是“Snake”匹配“Rattlesnake”中的一部分。
答案 0 :(得分:4)
这是一种能够完成工作的黑客:
public IQueryable<Monitoring> GetMonitoringList(string[] animalValues)
{
var values = animalValues.Select(x => "," + x + ",");
var result = from m in db.Monitorings
where values.Any(c => ("," + m.AnimalType + ",").Contains(c))
select m;
return result;
}
通过这种方式,您将拥有
并检查“,狮子”和“山狮”将不匹配。
这很脏,我知道。
答案 1 :(得分:2)
因为您的字段中的数据是逗号分隔的,所以您确实需要单独分解这些条目。由于SQL实际上并不支持分割字符串的方法,因此我提出的选项是执行两个查询。
第一个查询使用您开始使用的代码来至少让您进入大球场,并最大限度地减少您要检索的数据量。它将其转换为List<>
以实际执行查询并将结果存入内存,这将允许访问更多扩展方法,如Split()
。
第二个查询使用内存中的数据子集并将其与数据库表连接,然后提取完全匹配:
public IQueryable<Monitoring> GetMonitoringList(string[] animalValues)
{
// execute a query that is greedy in its matches, but at least
// it's still only a subset of data. The ToList()
// brings the data into memory, so to speak
var subsetData = (from m in db.Monitorings
where animalValues.Any(c => m.AnimalType.Contains(c))
select m).ToList();
// given that subset of data in the List<>, join it against the DB again
// and get the exact matches this time
var result = from data in subsetData
join m in db.Monitorings on data.ID equals m.ID
where data.AnimalType.Split(',').Intersect(animalValues).Any ()
select m;
return result;
}