使用实体框架查询许多(约100个)搜索项

时间:2013-01-19 11:39:45

标签: c# entity-framework entity-framework-5

我需要对我的数据库进行查询,这可能是这样的,实际上可能有100个或更多的搜索词。

public IQueryable<Address> GetAddressesWithTown(string[] towns)
{
    IQueryable<Address> addressQuery = DbContext.Addresses;
    addressQuery.Where( x => towns.Any( y=> x.Town == y ) );
    return addressQuery;
}

但是当它包含超过15个术语时,它会在执行时抛出异常,因为生成的SQL太长。

可以通过Entity Framework完成此类查询吗?

还有哪些其他选项可以完成这样的查询?

3 个答案:

答案 0 :(得分:3)

对不起,我们是在谈论这个精确的SQL吗?

在这种情况下,这是一个非常简单的“睁开眼睛”。

有一种方法(包含)将该字符串映射到IN子句,这导致一个sql条件(('','','')中的城镇)

让我看看我是否做对了:

  

addressQuery.Where(x =&gt; towns.Any(y =&gt; x.Town == y));

应该是

  

addressQuery.Where(x =&gt; towns.Contains(x.Town)

生成的SQL将会小一些。 100项仍在征税 - 我敢说你可能在这里有数据库或应用程序设计问题,这需要业务方面的分析,我在20年内没有这个要求我使用数据库。

答案 1 :(得分:1)

这看起来像是一个你想要使用PredicateBuilder的场景,因为这将帮助你创建一个基于的谓词并构建你的动态lambda表达式。

这是由Joseph Albahari创建LinqPad的名为LinqKit的库的一部分。

 public IQueryable<Address> GetAddressesWithTown(string[] towns)
{
  var predicate = PredicateBuilder.False<Address>();

  foreach (string town in towns)
  {
    string temp = town;
    predicate = predicate.Or (p => p.Town.Equals(temp));
  }

  return DbContext.Addresses.Where (predicate);
}

答案 2 :(得分:0)

你有两个选择:

  • 您可以使用.Any替代方案替换.Contains
  • 您可以将纯SQL与表值参数一起使用。

使用.Contains更容易实现,并且有助于提高性能,因为它转换为内联sql IN子句;所以100个城镇应该不成问题。但是,这也意味着确切的sql取决于城镇的确切数量:你迫使sql-server重新编译每个城镇数量的查询。当查询复杂时,这些重新编译可能很昂贵;他们也可以从缓存中驱逐其他查询计划。

使用表值参数是更通用的解决方案,但实现起来还要多,特别是因为这意味着您需要自己编写SQL查询,而不能依赖实体框架。 (使用ObjectContext.Translate,您仍然可以将查询结果解压缩为强类型对象,尽管编写了sql)。不幸的是,你不能使用实体框架来有效地将大量数据传递给sql server。实体框架不支持表值参数,也不支持临时表(但它是commonly requested feature)。

一些TVP sql看起来像select ... from ... join @townTableArg townArg on townArg.town = address.townselect ... from ... where address.town in (select town from @townTableArg)

你可能可以围绕EF限制工作,但它不会很快并且可能会很棘手。解决方法是将您的值插入到某个中间表中,然后再加入 - 这仍然是100个插入,但这些是单独的语句。如果EF的未来版本支持batch CUD statements,那么这可能会合理地起作用。

几乎等同于表值参数将是批量插入临时表并与查询中的表连接。大多数情况下,这只是意味着您的表名将以“#”开头,​​而不是“@”:-)。临时表有更多的开销,但您可以在其上和一些情况下放置索引,这意味着后续查询将更快(对于非常大的数据量)。

不幸的是,使用临时表或C#批量插入是一件麻烦事。这里最简单的解决方案是制作DataTable;这可以传递给任何一个。但是,数据表相对较慢;一旦你开始添加数百万行,结束可能是相关的。最快(一般)的解决方案是实现自定义IDataReader,几乎和IEnumerable<SqlDataRecord>一样快。

顺便说一下,要使用表值参数,需要在服务器上声明表参数的形状(“type”);如果你使用临时表,你也需要创建它。

一些可以帮助您入门的指示: