2011-07-21 4 views
2

こんにちは、私は「EF4.xN:Enitityフレームワーク4.xのペイロードを持つメートル

に次の関係を作成するために必死に素材が一定量に多くの材料で作られており、各材料を用いることができるものをしようとしています資料1:N MaterialUsage 『と『MaterialUsageのM:1素材』素材」:M材質が、内容はペイロードであるので、私はそれに翻訳した

材料に変換します理想的なN』で

私はpaylを持っているので2つのテーブルを作成しましたOAD(一定量)

「素材」や材質の「MaterialUsage」

私は関係を定義した「IsMadeOf」「MaterialUsage.IsUsedIn」と 関係にリンクする「IsUsedFor」「MaterialUsageにリンク.IsMadeOf '

in MaterialUsage私は上記の2つの「コンテンツ」を別にしています。

今私の問題へ:

私は基本的に言って、私は、エラーメッセージに遭遇する素材を削除すると、その関係を識別する協会MaterialMaterialUsage '、内の「Material.IsUsedFor <を - > MaterialUsage.IsMadeOf」、リレーションはステータス「削除済み」にあり、多重度の定義により、対応する「MaterialUsage」レコードはステータス「削除済」にも存在しなければならず、これは見つからなかった。

ただし、「Material.IsMadeOf」によって識別されたすべての 'MaterialUsages'およびすべての 'MaterialUsages'を削除することを意図しています。参照されたマテリアルは含まれていませんが、削除されるマテリアルに 'IsUsedIN'の参照を持つ 'MaterialUsage'レコードのみが含まれます。

わかりやすく理解してもらいたいと思います。

今私はそうする明確な方法を見つけようとしています。私は参照整合性と動作することができると推測していますが、私はあまりにもそれに精通していないと私のために失われています。

誰でも私を助けることができます - 私はDBデザインを問題なく変更できます。

ご協力いただきありがとうございます。

答えて

1

回答と質問の半分を試してみます。私は、ナビゲーションを設定している

public class MyContext : DbContext 
{ 
    public DbSet<Material> Materials { get; set; } 
    public DbSet<MaterialUsage> MaterialUsages { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Material>() 
      .HasMany(m => m.IsMadeOf) 
      .WithRequired(m => m.IsUsedIn) 
      .WillCascadeOnDelete(false); 

     modelBuilder.Entity<Material>() 
      .HasMany(m => m.IsUsedFor) 
      .WithRequired(m => m.IsMadeOf) 
      .WillCascadeOnDelete(false); 
    } 
} 

public class Material 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public ICollection<MaterialUsage> IsMadeOf { get; set; } 
    public ICollection<MaterialUsage> IsUsedFor { get; set; } 
} 

public class MaterialUsage 
{ 
    public int Id { get; set; } 
    public int Content { get; set; } 
    public Material IsUsedIn { get; set; } 
    public Material IsMadeOf { get; set; } 
} 

そして、この派生コンテキストとマッピング:DbContext APIとEF 4.1で、私は、次のモデルクラスを(私は私が正しくあなたの説明を理解願っています)を作成します特性はMaterialUsageRequiredであるので、材料に言及せずにMaterialUsageが存在しないと思います。そうですか?私が見る限り、カスケード削除をオフにする必要があります。さもなければ、EFは許容されていないマルチプル可能カスケード削除パスについて文句を言います。このような何かがうまくいく材料とそれらの関係を作成するために、今すぐ

、:

using (var context = new MyContext()) 
{ 
    var copper = new Material { Name = "Copper" }; 
    context.Materials.Add(copper); 

    var zinc = new Material { Name = "Zinc" }; 
    context.Materials.Add(zinc); 

    var brass = new Material 
    { 
     Name = "Brass", 
     IsMadeOf = new List<MaterialUsage> 
     { 
      new MaterialUsage { Content = 10, IsMadeOf = copper }, 
      new MaterialUsage { Content = 20, IsMadeOf = zinc } 
     } 
    }; 
    context.Materials.Add(brass); 

    context.SaveChanges(); 
} 

結果をデータベースには、次のとおりです。

Table Materials   Table MaterialUsages 

Id Name    Id Content IsUsedIn_Id IsMadeOf_Id 
---------    ------------------------------------------- 
1 Brass    1  10   1    2 
2 Copper    2  20   1    3 
3 Zinc 

Materialは両方の関係の中で表示されますので、削除することは困難です。特に、私はあなたがこれを実現できたのか分からない:

私の意図は、材料とスルー識別されているすべての 「MaterialUsages」を削除することがある「Material.IsMadeOf」

私は理解していればこれを正しくあなたは亜鉛を削除するには、このような何かをしたいと思います:

var zinc = context.Materials 
    .Include(m => m.IsMadeOf) 
    .Where(m => m.Name == "Zinc") 
    .Single(); 
foreach (var usage in zinc.IsMadeOf.ToList()) 
    context.MaterialUsages.Remove(usage); 
context.Materials.Remove(zinc); 
context.SaveChanges(); 

亜鉛は、空の何もない(IsMadeOfコレクションで作られたので、上記のループはありませんされているため、これは動作しません。何もない)。しかし、あなたが亜鉛を今取り除くと、あなたは真鍮にのために使用される、すなわち、亜鉛がであるという制約に違反します。 (ID = MaterialUsages表2は、亜鉛なしでは存在できない。)

I私の意見はあなたがMaterial.IsUsedForによって識別されMaterialUsagesを削除する必要があります。

var zinc = context.Materials 
    .Include(m => m.IsMadeOf) 
    .Include(m => m.IsUsedFor) 
    .Where(m => m.Name == "Zinc") 
    .Single(); 
foreach (var usage in zinc.IsMadeOf.ToList()) 
    context.MaterialUsages.Remove(usage); 
foreach (var usage in zinc.IsUsedFor.ToList()) 
    context.MaterialUsages.Remove(usage); 
context.Materials.Remove(zinc); 
context.SaveChanges(); 

これはでID = 3を削除しますMaterialsテーブル、またMaterialsUsagesテーブルではId = 2となり、参照制約を完全に満たすようになりました。

これが望ましいかどうかわかりません。あなたが実際にあなたは亜鉛を削除します違反制約が原因でスローされる例外を持つようにをしたい:

編集

私は今見ると信じています。理由:他の材料で使用されている限り、材料を削除することはできません(亜鉛は真ちゅうで使用されるため、真鍮がデータベースにある限り亜鉛を削除することは禁じられています)。 OK、その後、一例では真鍮で亜鉛を交換すると、実際に動作します:

var brass = context.Materials 
    .Include(m => m.IsMadeOf) 
    .Where(m => m.Name == "Brass") 
    .Single(); 
foreach (var usage in brass.IsMadeOf.ToList()) 
    context.MaterialUsages.Remove(usage); 
context.Materials.Remove(brass); 
context.SaveChanges(); 

それはちょうどMaterial表にMaterialUsagesテーブルと真鍮の両方の行を削除します。

編集2

削除するための材料が他の材料のために使用されているかどうかを確認したい場合は、あなたが実際に削除しようとする前に、あなたはこれをテストできます。

if (context.Materials 
    .Where(m => m.Name == "Brass") 
    .Select(m => !m.IsUsedFor.Any()) 
    .Single()) 
{ 
    // the code snippet above 
} 
else 
{ 
    // "Brass" cannot be deleted since it is used for other materials... 
} 
+0

は詳細をありがとう回答。 – mph

+0

申し訳ありません - システムに騙されました。詳しい答えをありがとう。カスケード削除がEFルールに違反していることを確認できて非常にうれしく思います。また、参照制約に準拠した削除についても取り組んでいます。違反を検出するためにExceptionを使用するという考えは、実際には魅力的です。私は写真を投稿することは許可されていないので、あなたが正しくセットアップしたモデルのEFデザイナーの表現を投稿できませんでした。しかし、あなたの編集のインクルードが実際に必要かどうかは疑問です。 'code'fore''codeと' code'.ToList() 'code'は強制的に負荷を強制しませんか? – mph

+0

@mph:遅延ロードを使用する場合は 'Include'は必要ありません(ナビゲーションプロパティは遅延読み込みを有効にするために' virtual'でなければなりません)。しかし、あなたは '' Include'を遅延ロードとも活用することができます:DBへのラウンドトリップは1回だけで、遅延ロードは2回あります。例外をキャッチして評価する代わりに、削除しようとする素材が他の素材に使用されているかどうかを確認することもできます。私はこれを確認する方法を私の答えに追加しました。 – Slauma

関連する問題