实体框架:Enumerable.Contains的预编译查询
本文关键字:编译 查询 Contains 框架 Enumerable 实体 | 更新日期: 2023-09-27 18:17:50
实体框架5+应该预编译所有查询。但是,对于像
这样的查询,List<Guid> ids;
var entities = context.MyEntities.Where(x => ids.Contains(x.Id)).ToArray();
Entity Framework不能预编译查询,并且根据整个查询的复杂程度,将表达式树解析为SQL可能需要几秒钟的时间。有没有人找到一个变通方法来获得预编译查询?我真的不明白为什么会这么难;当然,使用参数很难做到这一点,因为元素的数量可以不同,但是使用像
这样的SQL就足够了。SELECT a, b, c from MyEntities
WHERE c in __PLACEHOLDER__
,然后用实际的列表元素替换占位符。当然,它不像传递参数那么好,但它比等待几秒钟反复解析整个表达式树要好得多。
您必须首先了解"IN"操作符在参数化SQL查询中的工作原理。
SELECT A FOM B WHERE C IN @p
不起作用,SQL命令参数不接受ARRAY作为参数值,而是将查询转换为
SELECT A FROM B WHERE C IN (@p1, @p2, @p3 ... etc)
这个查询有可变数量的参数,这就是为什么没有办法用IEnumerable.Contains
预编译这个查询。
唯一的其他选择(很长很长的路)是使用Xml或Json(将在Sql 2016中出现)。
Save your IEnumerable as xml.
[10,20,20,50] can be translated to
<data>
<int value="10"/>
<int value="20"/>
<int value="20"/>
<int value="50"/>
</data>
然后你可以定义一个参数为
的VIEW
SELECT INT FROM Xml(@P1)
你可以使用这个视图,但是在EF中有更多的挑战,如何触发这个查询,但是这个查询可以预编译,因为它只有一个参数。
自定义SQL for Performance Hack对于非常简单的查询,如
List<Guid> ids;
var entities = context.MyEntities.Where(x => ids.Contains(x.Id)).ToArray();
我可以简单地使用自定义SQL语句,然后输入
var parameterList = ids.Select(
(x,i)=> new SqlCommandParameter(
"@p"+i, x));
var pnames = String.Join(",", parameterList.Select(x=> x.ParameterName));
var entities =
context.SqlQuery<MyEntity>(
"SELECT * FROM TABLE WHERE Id in (" + pnames + ")",
parameterList.ToArray());
临时表也可以使用临时表,但这会增加数据库中活动事务的数量。
Guid sid = Guid.NewGuid();
foreach(var p in ids){
db.TempIDs.Add(new TempID{ SID = sid, Value = p });
}
db.SaveChanges();
var qIDs = db.TempIDs.Where( x=> x.SID == sid );
var myEntities db.MyEntities.Where( x => qIDs.Any( q.Value == x.Id) );
// delete all TempIDs...
db.SqlQuery("DELETE FROM TempIDs WHERE SID=@sid,
new SqlCommandParameter("@sid", sid));