2011-07-19 40 views
10

我使用EF4.1代碼第一和TPT(Table per Type)繼承。我有這樣的結構代碼第一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約束它的工作原理,但我想可以指定該使用模型構建器或在代碼中的一些其他方式。這可能嗎?

在此先感謝!

此致

西蒙

回答

9

當涉及到數據庫,TPT inheritance與基礎類(例如產品)和所有派生類(例如SpecializedProduct)之間的Shared Primary Key Association實現。現在,當您刪除一個Customer對象而沒有獲取其Products屬性時,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 


這就是說,有沒有辦法使產品和專用產品表之間的級聯刪除成爲可能,這就是EF Code First如何實現TPT繼承,並且不能覆蓋它。

那麼有什麼解決方案?

一種方法是你已經想通了,手動切換產品和SpecializedProduct表之間的級聯,以避免該異常,當你刪除一個客戶與SpecializedProducts。

第二種方法是在移除客戶時讓EF處理客戶的SpecializedProducts。就像我之前說過的那樣,這是因爲Customer對象沒有被正確提取,而且EF不知道客戶的SpecializedProducts,這意味着通過正確獲取客戶對象,Ef將開始跟蹤客戶的關聯並提交必要的SQL語句以確保每一個相關的記錄刪除客戶之前,刪除:

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來手動定義模型創建級聯刪除。 –