2011-03-21 64 views
7

私は以下の概念モデルを持っています。複数のタグ(複数の関係、多対多の関係)を持つストーリーがあり、各タグは特定のカテゴリに属します。エンティティフレームワーク:重複の挿入を避ける

私のデータは外部ソースからのもので、挿入する前に重複したタグが追加されていないことを確認します。

更新されたコードスニペット:

static void Main(string[] args) 
    { 
     Story story1 = new Story(); 
     story1.Title = "Introducing the Entity Framework"; 
     story1.Tags.Add(new Tag { Name = ".net", }); 
     story1.Tags.Add(new Tag { Name = "database" }); 

     Story story2 = new Story(); 
     story2.Title = "Working with Managed DirectX"; 
     story2.Tags.Add(new Tag { Name = ".net" }); 
     story2.Tags.Add(new Tag { Name = "graphics" }); 

     List<Story> stories = new List<Story>(); 
     stories.Add(story1); 
     stories.Add(story2); 

     EfQuestionEntities db = new EfQuestionEntities(); 

     Category category = (from c in db.Categories 
          where c.Name == "Programming" 
          select c).First(); 

     foreach (Story story in stories) 
     { 
      foreach (Tag tag in story.Tags) 
      { 
       Tag currentTag = tag; 
       currentTag = GetTag(tag.Name, category, db); 
      } 

      db.Stories.AddObject(story); 
     } 

     db.SaveChanges(); 
    } 

    public static Tag GetTag(string name, Category category, EfQuestionEntities db) 
    { 
     var dbTag = from t in db.Tags.Include("Category") 
        where t.Name == name 
        select t; 

     if (dbTag.Count() > 0) 
     { 
      return dbTag.First(); 
     } 

     var cachedTag = db.ObjectStateManager.GetObjectStateEntries(EntityState.Added). 
      Where(ose => ose.EntitySet == db.Tags.EntitySet). 
      Select(ose => ose.Entity). 
      Cast<Tag>().Where(x => x.Name == name); 

     if (cachedTag.Count() != 0) 
     { 
      return cachedTag.First(); 
     } 

     Tag tag = new Tag(); 
     tag.Name = name; 
     tag.Category = category; 

     db.Tags.AddObject(tag); 

     return tag; 
    } 

しかし、私はすでにのObjectContextに存在している同じのEntityKeyを持つオブジェクトについての例外を取得します。

また、else文を削除した場合、FK制約違反について例外が発生するため、Category属性がnullに設定されているようです。

答えて

4

私はEFで同じ問題を抱えていました。ここに私がやってしまったものです:story1.Tags.Add(GetTag(".net"))

  1. 代わりのstory1.Tags.Add(new Tag { Name = ".net", })を自分でやって、このようなヘルパーメソッドを介してすべてのTag作成をルーティング。
  2. GetTagメソッドは、コンテキスト内のタグをチェックして、既存のエンティティを返すかどうかを確認します。もしそうなら、それはそれを返します。
  3. 既存のエンティティが存在しない場合、ObjectStateManagerをチェックして、コンテキストに追加されたがまだデータベースに書き込まれていないエンティティがあるかどうかを確認します。一致するものが見つかった場合はTagを返します。
  4. まだTagが見つからない場合は、新しいTagが作成され、コンテキストに追加されてから返されます。

本質的には、あなたのプログラム全体でTag(すでに存在しているか作成されたもの)のインスタンスが複数使用されないようにします。

私のプロジェクトからいくつかのコード例が(Tagの代わりにInventoryItemを使用していますが、あなたはそのアイデアを得ています)。

ステップ3でのチェックは次のように行われます。

inventoryItem = new InventoryItem(); 
context.InventoryItems.AddObject(inventoryItem); 
return inventoryItem; 

更新:

ステップ3で検出されない Tag場合

// Second choice: maybe it's not in the database yet, but it's awaiting insertion? 
inventoryItem = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added) 
    .Where(ose => ose.EntitySet == context.InventoryItems.EntitySet) 
    .Select(ose => ose.Entity) 
    .Cast<InventoryItem>() 
    .Where(equalityPredicate.Compile()) 
    .SingleOrDefault(); 

if (inventoryItem != null) { 
    return inventoryItem; 
} 

が、ここではステップ4のコードです

このように使用してください。

Story story1 = new Story(); 
story1.Title = "Introducing the Entity Framework"; 
story1.Tags.Add(GetTag(".net", category, db)); 
story1.Tags.Add(GetTag("database", category, db)); 
+0

ありがとうございました!私は今それを試みます。ところで、あなたはまだそのようなピットに直面した後にEFを使用していますか? –

+0

@Mike:そうです。私の控えめなニーズを考えれば、私が解決できる方法を見つけることができなかったことは何もなかったし、EF(SubSonic)の前に私が使っていたことはさらに悪かった。 – Jon

+0

@Jon:このコードスニペットもありがとうございます。残念ながら、私はまだCategory = nullのトラッキング対象のエンティティがあることを意味するFK違反例外を受け取ります。 –

関連する問題