[英]Entity Framework: Precompiled Query for Enumerable.Contains
实体框架5+应该预先编译所有查询。 但是,对于诸如此类的查询
List<Guid> ids;
var entities = context.MyEntities.Where(x => ids.Contains(x.Id)).ToArray();
实体框架无法预编译查询,并且根据整体查询的复杂性,将表达式树解析为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中推出)。
将IEnumerable保存为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 A FROM B WHERE C IN(从Xml中选择INT(@ P1))
并且您可以使用此视图,但是在EF中如何触发此查询存在更多挑战,但此查询可以预编译,因为它只有一个参数。
自定义SQL for Performance Hack
对于非常简单的查询,
List<Guid> ids;
var entities = context.MyEntities.Where(x => ids.Contains(x.Id)).ToArray();
我可以简单地使用自定义SQL和fire,
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));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.