2011-07-19 7 views
10

私はEF4.1をコードファースト、TPT(タイプごとのテーブル)継承を使用しています。コードの最初のTPTと削除時のカスケード

public class Customer 
{ 
    public virtual ICollection<Product> Products {get; set;} 
} 

public class Product 
{ 
    [Required] 
    public int Id { get; set; } 

    [Required] 
    public virtual Customer {get; set;} 

    public decimal Price { get; set; } 
} 

public class SpecializedProduct : Product 
{ 
    public string SpecialAttribute { get; set; } 
} 

私は顧客を削除すると、その顧客に関連するすべての製品を削除したいと考えています。私は、顧客と製品の間(真)WillCascadeOnDeleteを指定することができます。

modelBuilder.Entity<Customer>().HasMany(e => e.Products).WithRequired(p => p.Customer).WillCascadeOnDelete(true); 

が、SpecializedProductと製品の間foreighnキーの関係がありますので、私は顧客を削除しようとするとき、私は例外を取得:

DELETE文がREFERENCE制約 "SpecializedProduct _TypeConstraint_From_Product_To_SpecializedProduct"と競合しました。競合は、データベース "Test"、テーブル "dbo.SpecializedProduct"、列 'Id'で発生しました。ステートメントは終了されました。

私は手動でそれが動作SpecializedProduct _TypeConstraint_From_Product_To_SpecializedProduct制約に削除カスケードに設定された、しかし、私は、ModelBuilderのか、コード内の他のいくつかの方法を使用してこれを指定できるようにしたい場合。これは可能ですか?

ありがとうございます!

よろしくは、それがデータベースになると

サイモン

答えて

9

TPT inheritanceは、基本クラスの間Shared Primary Key Association(例えば製品)を用いて実施され、すべての派生クラス(例えばSpecializedProduct)。これで、ProductsプロパティをフェッチせずにCustomerオブジェクトを削除すると、EFは、この顧客に、必要に応じて削除する必要のある製品がたくさんあることを知りません。必要に応じて得意先商品の関連付けをマークしてカスケード削除を有効にすると、データベースが商品テーブルから子レコードを削除しますが、この子レコードがSpecializedProductの場合、SpecializedProductの関連行が獲得されますあなたが得ている例外が削除されてしまいます。だから、基本的に次のコードは動作しません。

// This works only if customer's products are not SpecializedProduct 
Customer customer = context.Customers.Single(c => c.CustomerId == 1); 
context.Customers.Remove(customer); 
context.SaveChanges();  

このコードをEFの原因になりますデータベースに次のSQLを提出する:

exec sp_executesql N'delete [dbo].[Customer] where ([CustomerId] = @0)',N'@0 int',@0=1 
言っ


が、方法はありませんProductテーブルとSpecializedProductテーブル間のカスケード削除を有効にするには、EFコードファーストがTPT継承をどのように実装し、それをオーバーライドすることはできません。

解決策は何ですか?

SpecializedProductsを使用して顧客を削除するときの例外を避けるために、ProductとSpecializedProductテーブル間のカスケードを手動で切り替えるという方法があります。

2番目の方法は、顧客を取り除くときにEFが顧客のSpecializedProductsを処理するようにすることです。前にも述べたように、これはCustomerオブジェクトが適切にフェッチされておらず、EFは顧客のSpecializedProductsを認識していないため、顧客オブジェクトを適切にフェッチすることによって、Efは顧客の関連付けを追跡し、その結果、

Customer customer = context.Customers 
          .Include(c => c.Products) 
          .Single(c => c.CustomerId == 1); 

context.Customers.Remove(customer); 
context.SaveChanges();  

、EFは完全に順序ですべてを削除し、データベースに次のSQL文を提出する:すべての関連レコードが顧客を削除する前に除去されること

exec sp_executesql N'delete [dbo].[SpecializedProduct] where ([Id] = @0)',N'@0 int',@0=1 

exec sp_executesql N'delete [dbo].[Product] where (([Id] = @0) and ([Customer_CustomerId] = @1))',N'@0 int,@1 int',@0=1,@1=1 

exec sp_executesql N'delete [dbo].[Customer] where ([CustomerId] = @0)',N'@0 int',@0=1 
+3

それは13ヶ月かかりましたが、私は私の答えを得ました:-)ありがとう!私が覚えているように、いくつかのSQLを実行してモデル作成時に手動でカスケード削除を定義することになりました。 –

関連する問題