LINQ返回记录,其中string []值与逗号分隔的字符串字段匹配

时间:2012-07-03 00:48:00

标签: linq entity-framework-4 csv contains

我正在尝试使用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”中的一部分。

2 个答案:

答案 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;
}

通过这种方式,您将拥有

  • “狮子,老虎,山羊,”
  • “蛇,狮子,马,”
  • “响尾蛇,”
  • “,Mountain Lion,”

并检查“,狮子”和“山狮”将不匹配。

这很脏,我知道。

答案 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;
}