Afaik Entity Framework 6不支持批量插入/更新/删除。 无论如何都要对IQueryable对象进行批量更新。作为一个例子,我有
var query = _db.People.Where(x=>x.Name.Contains(parameter));
一个IQueryable(查询)对象,我想获取生成的sql。然后我希望我可以使用这个选择查询创建一个更新命令,如此
Update filteredPerson
Set filteredPerson.Status = 'Updated'
from (here it comes IQueryable Generated SQL :) ) as filteredPerson
over DbContext raw sql execution commands。顺便说一下,我不需要改变跟踪和自动检测等EF属性。这只是一个批处理操作。
我知道它风险很大,但我会将它用于一小段代码。
其他一些逻辑被批准。如果你知道更好的事情,我想听听。
原因:为什么我要这样做,因为我不想破坏图层的分离。并且有一些验证和过滤从其他层进入可查询对象。因此很难将其转换为存储过程。另一方面,它必须比其他标准查询更快。
我再次知道实体框架6中没有批处理操作的支持。但其他问题有点过时了。这是我想再问这个问题的另一个原因。
答案 0 :(得分:3)
在我写这个问题的时候,我在猜测我将如何解决它。但我正在寻找一些更合适的方法。最后,我知道我在做什么,并试图在我之后寻找相同代码的同事们变得简单。我知道它有一些风险用法,但我让CLR的例外来处理它。在这个借口:)之后,我写了这样的代码:
让我们说我有一个以这种方式生成的IQueryable对象:
string parameter = "John";
AdventureWorks2012Entities _db = new AdventureWorks2012Entities();
var query = _db.People.AsQueryable();
//Some parameters added from different layers
query = query.Where(x => x.FirstName.Contains(parameter));
然后我想要对这个IQueryable对象进行批量更新。
var sqlFrom = query.ToString(); //This is the query which becomes "from table"
var dbq = query.AsDbQuery().GetObjectQuery(); //This does some magic with reflection
var linqParams = dbq.Parameters
.Select(x => new System.Data.SqlClient.SqlParameter(x.Name, x.Value)).ToList();
linqParams.Add(new System.Data.SqlClient.SqlParameter("@ModDate", DateTime.Now));
var sqlBatchUpdate = @"Update filteredPerson Set ModifiedDate = @ModDate From (@FilteredPerson) as filteredPerson"
.Replace("@FilteredPerson", sqlFrom);
var affectedRows = _db.Database.ExecuteSqlCommand(sqlBatchUpdate, linqParams.ToArray());
那就是它!现在我不必再次在存储过程中重复相同的业务逻辑。它比foreach和SaveChanges组合更快。
所以我最终得到了这个非常基本的用法。作为快速解决方案毫无疑问它带来了更多问题!但我知道我可以轻松地将其包裹起来以达到新的目的。因此,程序员希望以更多的偏好使用它。
此外,执行反射和转换的代码如下所示,我为完整代码添加了一个要点:
public static ObjectQuery<T> GetObjectQuery<T>(this DbQuery<T> query)
{
var internalQueryField = query.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(f => f.Name.Equals("_internalQuery"))
.FirstOrDefault();
var internalQuery = internalQueryField.GetValue(query);
var objectQueryField = internalQuery.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(f => f.Name.Equals("_objectQuery"))
.FirstOrDefault();
var objectQuery = objectQueryField.GetValue(internalQuery) as ObjectQuery<T>;
return objectQuery;
}
这是Gist file。希望它可以帮助那些人。