【问题标题】:Retrieve all values that partly contains values from a list从列表中检索部分包含值的所有值
【发布时间】:2013-12-24 17:57:52
【问题描述】:

我的数据库中有一个名为Citites 的表。我想检索名称包含strings 列表中任何值的所有城市。

List<string> strings = new List<string>(new string[] {"burg", "wood", "town"} );

我试过了,但它只会匹配字符串列表中的确切值。我需要找到包含例如town 的值,例如cape towntownsend

List<City> cities = db.Cities.Where(c => strings.Contains(c.name));

编辑
我正在使用 LINQ to SQLAny() 这里似乎不支持:

在查询的 LINQ to SQL 实现中不能使用本地序列 除包含运算符外的运算符。

【问题讨论】:

  • 对于这样的问题,请务必注意您使用的是哪种 LINQ 提供程序 - 是 Linq-to-sql、实体框架(然后是哪个版本)等。这是因为每个提供程序都支持一组不同的表达式。
  • @Knaģis - 好点,它已经更新了。

标签: c# linq linq-to-sql


【解决方案1】:

假设您的 LINQ 提供程序支持它,这将满足您的需求 - 因为您没有提及您使用的是什么,所以我们无法对其进行测试。

List<City> cities = db.Cities.Where(c => strings.Any(s => c.name.Contains(s)));

详细说明:对于单个值(如Capetown),您将编写

strings.Any(s => "Capetown".Contains(s))

然后您只需在当前的Where 条件中应用此表达式,如初始代码示例所示。

【讨论】:

  • c 是一个有属性名称的城市,所以 c.Contains 不起作用。
  • 我不支持Any()
【解决方案2】:

由于您提到您的 LINQ 提供程序在这种情况下不支持 .Any(),因此这里有一个更复杂的代码,可以动态构建查询表达式。

var strings = new [] { "burg", "wood", "town" };
// just some sample data
var cities = new[] { new City("Capetown"), new City("Hamburg"), new City("New York"), new City("Farwood") };

var param = Expression.Parameter(typeof(City));
var cityName = Expression.PropertyOrField(param, "Name"); // change the property name
Expression condition = Expression.Constant(false);
foreach (var s in strings)
{
    var expr = Expression.Call(cityName, "Contains", Type.EmptyTypes, Expression.Constant(s));
    condition = Expression.OrElse(condition, expr);
}

// you can apply the .Where call to any query. In the debugger view you can see that
// the actual expression applied is just a bunch of OR statements.
var query = cities.AsQueryable().Where(Expression.Lambda<Func<City, bool>>(condition, param));
var results = query.ToList();

// the class used in the test
private class City
{
    public City(string name) { this.Name = name; }
    public string Name;
}

但请注意,由于您在其他 cmets 中提到 strings 集合相当大,因此您应该真正考虑构建一个存储过程并将值作为 XML 参数传递给该过程(然后将 XML 作为表加载并加入它在查询中)因为这种构建查询的方法可能很快就会遇到某种“查询有太多操作数”的异常。

【讨论】:

  • 这是我采用的解决方案。我不知道这是否最快,但它解决了我的问题。
【解决方案3】:

我不确定您的 LINQ 提供者是否支持它,但至少在 LINQ-To-Objects 中这是可行的:

List<City> cities = db.Cities.Where(c => strings.Any(s=> c.Name.Contains(s)));

【讨论】:

  • 我正在运行 LINQ-to-SQL,但它似乎不受支持。
【解决方案4】:

您需要检查城市名称是否包含列表中的任何字符串,而不是相反:

protected bool ContainsSubstring(string cityName, List<string> strings)
{
 foreach(string subString in strings)
 {
  if (cityName.Contains(subString)) return true;
 }
 return false;
}

...

List<City> cities = db.Cities.Where(c => this.ContainsSubstring(c.name, strings));

【讨论】:

  • 如果您不支持 Any(),这应该可以。
  • 如果我的 strings 列表中有 200 个值,那将是很多调用。这真的是解决它的唯一方法吗?
  • 为了不做这么多的db调用,你可以定义自己的谓词,一次检查所有子字符串,我会编辑我的帖子。
  • 现在它应该可以工作了,对数据库的调用更少了。只需在同一个类中添加 ContainsSubstring 方法即可使该特定调用起作用。或者您可以更改调用,也许将方法设为静态。
【解决方案5】:

如果您发现它有很多循环,请尝试使用 FUNC 会更好(在性能方面)。我有一个样本:

            List<string> _lookup = new List<string>() { "dE", "SE","yu" };
            IEnumerable<string> _src = new List<string> { "DER","SER","YUR" };

            Func<string, List<string>, bool> test = (i,lookup) =>
            {
                bool ispassed = false;

                foreach (string lkstring in lookup)
                {
                    ispassed = i.Contains(lkstring, StringComparison.OrdinalIgnoreCase);

                    if (ispassed) break;
                }

                return ispassed;

            };


            var passedCities = _src.Where(i => test(i, _lookup));

【讨论】:

    【解决方案6】:
    var cities = from c in db.Cities.AsEnumerable()
                 from s in strings
                 where c.name.ToLower().Contains(s.ToLower())
                 select c.name;
    

    【讨论】:

      【解决方案7】:

      你有能力调用存储过程或 sql 吗? - 您可以使用 SQL 全文搜索,尤其是在搜索多个术语时。它可能比在 SQL 中进行字符串比较要快得多。

      http://technet.microsoft.com/en-us/library/ms142583.aspx

      你可以通过string.Join(" ", strings)创建你的搜索词

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-11
        • 2017-11-19
        • 2017-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多