1

我需要对我的数据库进行查询,这可能是这样的,实际上可能有 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吗?

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

4

3 回答 3

3

抱歉,我们在谈论这个确切的 SQL 吗?

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

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

让我看看我是否正确:

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

应该

addressQuery.Where (x => towns.Contains (x.Town)

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

于 2013-01-19T12:05:36.307 回答
1

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

这是创建 LinqPad 的 Joseph Albahari 名为 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);
}
于 2013-01-19T11:48:05.107 回答
0

您有两种选择:

  • 您可以替换.Any.Contains替代品。
  • 您可以使用带有表值参数的普通 SQL。

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

使用 table-valued-parameters 是更通用的解决方案,但实现起来需要更多的工作,特别是因为这意味着您需要自己编写 SQL 查询并且不能依赖实体框架。(使用ObjectContext.Translate你仍然可以将查询结果解包为强类型对象,尽管编写了 sql)。不幸的是,您还不能使用实体框架将大量数据有效地传递给 sql server。实体框架不支持表值参数,也不支持临时表(不过,这是一个普遍要求的特性)。

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

您可能可以解决 EF 限制,但它不会很快并且可能会很棘手。一种解决方法是将您的值插入到某个中间表中,然后加入其中 - 这仍然是 100 次插入,但这些是单独的语句。如果 EF 的未来版本支持批处理 CUD 语句,这实际上可能会合理地工作。

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

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

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

一些帮助您入门的建议:

于 2013-01-19T11:57:45.677 回答