回答と質問の半分を試してみます。私は、ナビゲーションを設定している
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で、私は、次のモデルクラスを(私は私が正しくあなたの説明を理解願っています)を作成します特性はMaterialUsage
〜Required
であるので、材料に言及せずに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...
}
は詳細をありがとう回答。 – mph
申し訳ありません - システムに騙されました。詳しい答えをありがとう。カスケード削除がEFルールに違反していることを確認できて非常にうれしく思います。また、参照制約に準拠した削除についても取り組んでいます。違反を検出するためにExceptionを使用するという考えは、実際には魅力的です。私は写真を投稿することは許可されていないので、あなたが正しくセットアップしたモデルのEFデザイナーの表現を投稿できませんでした。しかし、あなたの編集のインクルードが実際に必要かどうかは疑問です。 'code'fore''codeと' code'.ToList() 'code'は強制的に負荷を強制しませんか? – mph
@mph:遅延ロードを使用する場合は 'Include'は必要ありません(ナビゲーションプロパティは遅延読み込みを有効にするために' virtual'でなければなりません)。しかし、あなたは '' Include'を遅延ロードとも活用することができます:DBへのラウンドトリップは1回だけで、遅延ロードは2回あります。例外をキャッチして評価する代わりに、削除しようとする素材が他の素材に使用されているかどうかを確認することもできます。私はこれを確認する方法を私の答えに追加しました。 – Slauma