4

SOでこれが何度も尋ねられたことは知っていますが、EF CFでナビゲーションプロパティを追加または更新する方法について決定的な答えを見つけることができません。

エンティティ (簡略化):

 public class Basket : EntityBase
    {
        public virtual List<Fruit> TaggedFruits { get; set; }
    } 

    public class Fruit : EntityBase
        {

        }

アクション結果:

 [HttpPost]
        public ActionResult SaveTags(Basket basket, int[] selectedFruits)
        {
        basket.TaggedFruits = new List<Fruits>();

        foreach (int guid in selectedFruits)
            basket.TaggedFruits.Add(repository.Fruits.FirstOrDefault(p => p.Id == guid));

        using (var context = new EFDbContext())
        {
            context.Baskets.Attach(basket);
            context.SaveChanges();
        }

        return RedirectToAction("GetBasket", new {guid = basket.Guid});
    }

上記の SaveTags メソッドを何度も繰り返してみましたが、うまくいきませんでした。これはスローします:

エンティティ オブジェクトは、IEntityChangeTracker の複数のインスタンスによって参照できません。

here および他のサイトを調査した後、エラーは明らかに、私のリポジトリパターンと DBContext をメソッドに混在させると競合が発生することを示しています。

次の方法で、タグ付けをリポジトリに移動すると:

 [HttpPost]
            public ActionResult SaveTags(Basket basket, int[] selectedFruits)
            {
                   List<Fruit> taggedFruits = new List<Fruit>();
           foreach (int guid in selectedFruits)
               taggedFruits.Add(new Fruit {Id = guid});

           libraryRepository.TagBasket(basket, taggedFruits);

            return RedirectToAction("GetBasket", new {guid = basket.Guid});
        }



/*in repository*/
    public void TagBasket(Basket basket, List<Fruit> fruits )
            {
                basket.Taggedfruits = new List<Fruit>();
                foreach (var fruit in fruits)
                {
                    basket.Taggedfruits.Add(Fruit);
                }


            context.Baskets.Attach(basket);
       context.SaveChanges();
        }

その後、変更はデータベースにコミットされません。何も起こりません。誰かが私を正しい方向に向けることができますか? 私は長い間これと戦ってきました、ありがとう...

4

1 に答える 1

6

まあ、あなたはエンティティをアタッチするだけです(=状態をに設定しますUnchanged)そして を呼び出しますSaveChanges。その場合、何も変更されていないことをEFに伝えています->何も起こりません。

Basketとの間の関係を変更するにはTaggedFruits、データベースからバスケットの元の果物コレクションをロードし、ID コレクションの ID に従って、バスケットのロードされた果物コレクションからタグ付けされた果物を削除または追加する必要があります。

public void TagBasket(Basket basket, List<Fruit> fruits)
{
    var basketInDB = context.Baskets.Include(b => b.Taggedfruits)
        .Single(b => b.Id == basket.Id);

    foreach (var fruitInDB in basketInDB.Taggedfruits.ToList())
        if (!fruits.Any(f => f.Id == fruitInDB.Id))
            basketInDB.Taggedfruits.Remove(fruitInDB);

    foreach (var fruit in fruits)
        if (!basketInDB.Taggedfruits.Any(f => f.Id == fruit.Id))
        {
            var newFruit = new Fruit { Id = fruit.Id };
            context.Fruits.Attach(newFruit);
            basketInDB.TaggedFruits.Add(newFruit);
        }

    // Next line is only necessary if other properties in basket
    // could have been changed in your view
    context.Entry(basketInDB).CurrentValues.SetValues(basket);

    context.SaveChanges();
}

int[] selectedFruitsID のみが必要なため、コレクションをこのメソッドに渡すこともできます。

于 2012-04-24T16:03:10.060 に答える