我需要对我的数据库进行查询,这可能是这样的,实际上可能有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
完成此类查询吗?
还有哪些其他选项可以完成这样的查询?
答案 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
。使用.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.town
或select ... from ... where address.town in (select town from @townTableArg)
。
你可能可以围绕EF限制工作,但它不会很快并且可能会很棘手。解决方法是将您的值插入到某个中间表中,然后再加入 - 这仍然是100个插入,但这些是单独的语句。如果EF的未来版本支持batch CUD statements,那么这可能会合理地起作用。
几乎等同于表值参数将是批量插入临时表并与查询中的表连接。大多数情况下,这只是意味着您的表名将以“#”开头,而不是“@”:-)。临时表有更多的开销,但您可以在其上和一些情况下放置索引,这意味着后续查询将更快(对于非常大的数据量)。
不幸的是,使用临时表或C#批量插入是一件麻烦事。这里最简单的解决方案是制作DataTable
;这可以传递给任何一个。但是,数据表相对较慢;一旦你开始添加数百万行,结束可能是相关的。最快(一般)的解决方案是实现自定义IDataReader
,几乎和IEnumerable<SqlDataRecord>
一样快。
顺便说一下,要使用表值参数,需要在服务器上声明表参数的形状(“type”);如果你使用临时表,你也需要创建它。
一些可以帮助您入门的指示: