2

レコードが追加または更新されたトランザクションのリストの入力パラメーターを受け入れるメソッドがあります。

リストをループして、変更されたものと、次を使用して追加されたウィッシュを検出します。context.Entry(item).State = System.Data.EntityState.Modified; 各トランザクションの状態を設定します。

私が抱えている問題は、トランザクションの入力パラメータリストをループしているときにトランザクションオブジェクトがTransactionTypeと関係があるためです。データベースに同じトランザクションIDを持つトランザクションが複数ある場合、次のエラーが発生します。

同じキーを持つオブジェクトは、ObjectStateManagerにすでに存在します。ObjectStateManagerは、同じキーを持つ複数のオブジェクトを追跡できません。

  • ちなみに私はEF5とCodeFirstを使用しています。

問題の方法は次のとおりです。

public TransactionList SaveTransactions(Transaction[] transactions)
        {
            try
            {
                using (EntityContext context = new EntityContext())
                {
                    foreach (var item in transactions)
                    {
                        if (item.TransactionId > 0)
                            context.Entry(item).State = System.Data.EntityState.Modified;
                        else
                            context.Entry(item).State = System.Data.EntityState.Added;
                    }

                    context.SaveChanges();
                }
                return GetLatestTransactions();
            }

## UPDATE ## 各アイテムのTransactionTypeをnullに設定すると、エラーは発生せず、残りのトランザクションフィールドは正常に更新されます。つまり、TransAmount、Dateなどです。問題は、TransTypeをnullに設定すると、トランザクションのタイプを変更できなくなることです。

using (EntityContext context = new EntityContext())
{
  foreach (var item in transactions)
  {
    //set the fk to null
    item.TransactionType = null;

    if (item.TransactionId > 0)
    {
      context.Entry(item).State = System.Data.EntityState.Modified;
    }
    else
      context.Entry(item).State = System.Data.EntityState.Added;
    }
    context.SaveChanges();
}

##更新2## これが機能する別の方法を見つけましたが、それでも私にとっては理想的ではありません。アイテムごとに1つのトランザクションを取得してから、値を設定します。.Singleは反復ごとにラウンドトリップを実行するため、このソリューションは好きではありません。

foreach (var item in transactions)
{
  var or = context.Transaction
  .Include(t => t.Category)
  .Include(t => t.TransactionReasonType)
  .Include(t => t.TransactionType)
  .Single(t => t.TransactionId == item.TransactionId);

  if (item.TransactionId > 0)
  {
    context.Entry(or).CurrentValues.SetValues(item);
    context.Entry(or).State = System.Data.EntityState.Modified;
  }
4

2 に答える 2

1

私の問題の解決策は、追加と更新を分離することでした。更新するには、データベースから各行をフェッチして、元の値を新しい値に設定します。addの場合は、コンテキストに新しい値を追加するだけです。

foreach (var item in transactions)
{
  if (item.TransactionId > 0) //Update
  {
    var original = context.Transaction.Where(
                            t => t.TransactionId == item.TransactionId)
                          .FirstOrDefault();

    original.TransactionType = context.TypeTransaction.Single(
                           p => p.TypeTransactionId == item.TransactionType.TypeTransactionId);

    context.Entry(original).CurrentValues.SetValues(item);
  }
  else //Insert
  {    
    item.TransactionType = context.TypeTransaction.Single(
                           p => p.TypeTransactionId == item.TransactionType.TypeTransactionId);

    context.Transaction.Add(item);
  }
}

context.SaveChanges();
于 2013-02-12T07:39:07.250 に答える
0

この問題を回避する別の方法:

foreach (var item in updated)
{
   var original = db.MyEntities.Find(item.Id);
   db.Entry(original).CurrentValues.SetValues(item);
}
db.SaveChanges();
于 2013-08-16T19:11:34.310 に答える