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