批量更新/删除EF5(Batch update/delete EF5)

2019-06-18 10:36发布

什么是对付使用(实体框架)EF5批量更新的最佳方式? 我有2个特殊情况我感兴趣的:

  1. 更新字段(例如UpdateDate)为100和100.000之间的Id,该主键列表(列表)。 调用每个单独的更新似乎是太多开销和花费很长的时间。

  2. 插入很多,也是100和100.000之间,在一个单一的去相同的对象(如用户)。

任何好的建议吗?

Answer 1:

  1. 有两个开源项目,允许这样的: EntityFramework.Extended和实体框架的扩展 。 您还可以查看讨论关于EF英孚的CodePlex网站批量更新。
  2. 通过EF插入100K的记录是在第一时间错误的应用程序架构。 你应该选择不同的轻量化技术进行数据导入。 即使EF与这样大的唱片集内部操作将花费你大量的处理时间。 目前对于批量插入的EF无解,但有广泛的讨论关于EF代码丛网站这个功能。


Answer 2:

我看到下面的选项:

1。 最简单的方法-通过创建你的手SQL请求,并通过执行ObjectContext.ExecuteStoreCommand

context.ExecuteStoreCommand("UPDATE TABLE SET FIELD1 = {0} WHERE FIELD2 = {1}", value1, value2);

2。 使用EntityFramework.Extended

context.Tasks.Update(
    t => t.StatusId == 1, 
    t => new Task {StatusId = 2});

3。 制作自己的扩展EF。 有文章批量删除 ,其中这个目标是通过继承ObjectContext类实现。 这是值得去看一看。 批量插入/更新可以以同样的方式来实现。



Answer 3:

您可能不希望听到它,但你最好的选择是不使用EF进行批量操作。 对于跨越的记录更新表的字段,在数据库中(可能通过映射到EF功能一个存储过程调用)使用UPDATE语句。 您也可以使用Context.ExecuteStoreQuery方法问题的更新语句到数据库。

对于大量的插入,你最好的办法是使用大容量复制或SSIS。 EF将需要插入一个单独的匹配到数据库中的每一行。



Answer 4:

批量插入应该用SqlBulkCopy类来完成。 请参阅预先存在的StackOverflow Q&A上集成两个: 使用SqlBulkCopy和Entity Framework

SqlBulkCopy的是很多用户更友好比BCP(批量复制命令行实用程序),甚至开行集。



Answer 5:

    public static bool BulkDelete(string tableName, string columnName, List<object> val)
    {
        bool ret = true;

        var max = 2000;
        var pages = Math.Ceiling((double)val.Count / max);
        for (int i = 0; i < pages; i++)
        {
            var count = max;
            if (i == pages - 1) { count = val.Count % max; }

            var args = val.GetRange(i * max, count);
            var cond = string.Join("", args.Select((t, index) => $",@p{index}")).Substring(1);
            var sql = $"DELETE FROM {tableName} WHERE {columnName} IN ({cond}) ";

            ret &= Db.ExecuteSqlCommand(sql, args.ToArray()) > 0;
        }

        return ret;
    }


Answer 6:

我同意接受的答案是EF可能是错误的技术对于批量插入。 但是,我认为这是值得拥有看看EntityFramework.BulkInsert 。



Answer 7:

以下是我已经成功地完成:

private void BulkUpdate()
{
    var oc = ((IObjectContextAdapter)_dbContext).ObjectContext;
    var updateQuery = myIQueryable.ToString(); // This MUST be above the call to get the parameters.
    var updateParams = GetSqlParametersForIQueryable(updateQuery).ToArray();
    var updateSql = $@"UPDATE dbo.myTable
                       SET col1 = x.alias2
                       FROM dbo.myTable
                       JOIN ({updateQuery}) x(alias1, alias2) ON x.alias1 = dbo.myTable.Id";
    oc.ExecuteStoreCommand(updateSql, updateParams);
}

private void BulkInsert()
{
    var oc = ((IObjectContextAdapter)_dbContext).ObjectContext;
    var insertQuery = myIQueryable.ToString(); // This MUST be above the call to get the parameters.
    var insertParams = GetSqlParametersForIQueryable(insertQuery).ToArray();
    var insertSql = $@"INSERT INTO dbo.myTable (col1, col2)
                       SELECT x.alias1, x.alias2
                       FROM ({insertQuery}) x(alias1, alias2)";
    oc.ExecuteStoreCommand(insertSql, insertParams.ToArray());
}    

private static IEnumerable<SqlParameter> GetSqlParametersForIQueryable<T>(IQueryable<T> queryable)
{
    var objectQuery = GetObjectQueryFromIQueryable(queryable);
    return objectQuery.Parameters.Select(x => new SqlParameter(x.Name, x.Value));
}

private static ObjectQuery<T> GetObjectQueryFromIQueryable<T>(IQueryable<T> queryable)
{
    var dbQuery = (DbQuery<T>)queryable;
    var iqProp = dbQuery.GetType().GetProperty("InternalQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    var iq = iqProp.GetValue(dbQuery, null);
    var oqProp = iq.GetType().GetProperty("ObjectQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    return (ObjectQuery<T>)oqProp.GetValue(iq, null);
}


文章来源: Batch update/delete EF5