繁体   English   中英

实体框架:Enumerable.Contains的预编译查询

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM