实体框架和linq一起批处理更新



afaik实体框架6不支持批处理插入/update/delete。无论如何,是否可以通过可视化对象进行批处理更新。例如,我有

var query = _db.People.Where(x=>x.Name.Contains(parameter));

iQueryable(Query)对象,我想获得生成的SQL。然后,我希望我可以使用此选择查询创建一个更新命令

Update filteredPerson
Set filteredPerson.Status = 'Updated'
from (here it comes IQueryable Generated SQL :) ) as filteredPerson

通过dbContext RAW SQL执行命令。顺便说一句,我不需要EF属性,例如更改跟踪和自动检测。这只是一个批处理操作。

我知道这很风险,但我要把它用于一小部分代码。

其他一些逻辑也被化为。如果您知道一些更好的东西,我想听听。

原因:为什么我想这样做,因为我不想破坏层的分离。并且有一些验证,并且过滤来自其他层的可查询对象。因此,很难将其转换为存储过程。另一方面,它必须比其他标准查询更快。

再次,我知道实体框架6中没有支持批处理操作。但是其他问题已经过时了。这就是我要再次问这个的另一个原因。

在写这个问题时,我猜想我将如何解决它。但是我一直在寻找一些更合适的方法。最后,我知道我在做什么,并试图让我的同事们简单地看着我之后的相同代码。我知道它有一些风险的用法,但我让CLR的例外来处理它。在此借口之后:),我写了这样的代码:

假设我有一个以这种方式生成的可视化对象:

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;
}

这是要点文件。希望它能帮助某人。

最新更新