Linq to SQL にて複数行を DELETE

簡単な方法はありませんか? ADO.NET EF だと良い方法はありますか?

context.Table1.DeleteAllOnSubmit(
  from t1 in context.Table1
  where t1.Key1 == value
  select t1);

やったことある人も、やったことなくても挙動が想像できる人もいると思うけど、非常に効率が悪いことになっちゃうんですよね。

良い子は、素直にストアドプロシージャにしましょう。
とりあえず、

  var q = from t1 in context.Table1
          where t1.Key1 == value
          select t1;

に対して、q.Count() とすれば SELECT COUNT() FROM... WHERE... が発行されるように、DELETE FROM... WHERE... が発行できれば文句ないんだが、単純にはいかない。というわけで最終手段の文字列操作にて、

private static Regex regex = new Regex(
  @"\bSELECT\b.+?\bFROM\b(?<TableSource>.+?(?<SourceAlias> AS .+?))\bWHERE\b", RegexOptions.Singleline);

public static int DeleteAllOnImmediate<TEntity>(this DataContext context, IQueryable<TEntity> query)
{
  Debug.Assert(context != null);
  Debug.Assert(query != null);

  using (var cmd = context.GetCommand(query))
  {
    string sql = regex.Replace(cmd.CommandText, m =>
    {
      string source = m.Groups["TableSource"].Value;
      string alias = m.Groups["SourceAlias"].Value;
      string table = source.Substring(0, source.Length - alias.Length);

      return "DELETE " + table + " FROM " + source + " WHERE";
    }, 1);

    object[] parameters = new object[cmd.Parameters.Count];
    for (int i = 0; i < parameters.Length; i++)
      parameters[i] = cmd.Parameters[i].Value;

    return context.ExecuteCommand(sql, parameters);
  }
}

最初は DbCommand をまったく用いずに、IQueryable の ToString() メソッドから SQL を引っ張って、Expression プロパティと ExpressionVisitor を使ってパラメータを構築していた*1んだけど、ToString() を呼び出すのが嫌だったから DbCommand 経由に書き換え…。

良い子は、素直にストアドプロシージャにしましょう。*2

*1:クライテリアに List`1.Contain() とか含めると、IN 句に展開されるわけだけど、そうすると ParameterExpression と SQL のパラメータの数が不一致になって、すごく大変だったりした...

*2:大事なこと?なので2度書いてみました