(Entity Framework) EF5を使用してバッチ更新を処理する最良の方法は何ですか? 私が興味を持っている2つの特定のケースがあります:
主キーである 100 ~ 100.000 ID のリスト (List) のフィールド (UpdateDate など) を更新します。各更新を個別に呼び出すと、オーバーヘッドが大きくなり、時間がかかるようです。
100 ~ 100.000 の同じオブジェクト (ユーザーなど) を一度に多数挿入する。
良いアドバイスはありますか?
(Entity Framework) EF5を使用してバッチ更新を処理する最良の方法は何ですか? 私が興味を持っている2つの特定のケースがあります:
主キーである 100 ~ 100.000 ID のリスト (List) のフィールド (UpdateDate など) を更新します。各更新を個別に呼び出すと、オーバーヘッドが大きくなり、時間がかかるようです。
100 ~ 100.000 の同じオブジェクト (ユーザーなど) を一度に多数挿入する。
良いアドバイスはありますか?
次のオプションが表示されます。
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クラスを継承することでこの目標が達成された一括削除の記事があります。一見の価値があります。一括挿入/更新も同じ方法で実装できます。
聞きたくないかもしれませんが、EFを一括操作に使用しないのが最善の方法です。レコードのテーブル全体でフィールドを更新するには、データベースでUpdateステートメントを使用します(EF関数にマップされたストアドプロシージャを介して呼び出される可能性があります)。Context.ExecuteStoreQueryメソッドを使用して、データベースにUpdateステートメントを発行することもできます。
大規模な挿入の場合、最善の策はバルクコピーまたはSSISを使用することです。EFでは、挿入される行ごとにデータベースへの個別のヒットが必要になります。
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;
}
これが私が成功したことです:
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);
}
ef はおそらく一括挿入の間違ったテクノロジであるという受け入れられた回答に同意します。ただし、EntityFramework.BulkInsertを見る価値があると思います。