2011-07-19 23 views
10

Tôi đang sử dụng EF4.1 với mã đầu tiên và TPT (Bảng cho mỗi loại) thừa kế. Tôi có cấu trúc như thế nàyMã TPT đầu tiên và thác trên xóa

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; } 
} 

khi tôi xóa khách hàng, tôi muốn tất cả các sản phẩm liên kết với khách hàng đó sẽ bị xóa. Tôi có thể chỉ định một WillCascadeOnDelete (true) giữa khách hàng và các sản phẩm:

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

nhưng kể từ khi có một mối quan hệ quan trọng foreighn giữa SpecializedProduct và sản phẩm tôi nhận được một ngoại lệ khi tôi cố gắng để xóa các khách hàng:

Câu lệnh DELETE xung đột với ràng buộc REFERENCE "SpecializedProduct _TypeConstraint_From_Product_To_SpecializedProduct". Xung đột xảy ra trong cơ sở dữ liệu "Kiểm tra", bảng "dbo.SpecializedProduct", cột 'Id'. Các tuyên bố này đã bị chấm dứt.

Nếu tôi tự đặt một trên cascade delete trên SpecializedProduct _TypeConstraint_From_Product_To_SpecializedProduct hạn chế nó hoạt động, nhưng tôi muốn để có thể xác định điều này bằng cách sử dụng modelbuilder hoặc một số cách khác trong mã. Điều này có thể không?

Cảm ơn trước!

Trân trọng

Simon

Trả lời

9

Khi nói đến cơ sở dữ liệu, một TPT inheritance được thực hiện với một Shared Primary Key Association giữa lớp cơ sở (ví dụ sản phẩm) và tất cả các lớp học có nguồn gốc (ví dụ SpecializedProduct). Bây giờ, khi bạn xóa đối tượng Khách hàng mà không tìm nạp thuộc tính Sản phẩm của mình, EF không có ý tưởng rằng Khách hàng này có một loạt các sản phẩm cũng cần phải bị xóa theo yêu cầu của bạn. Nếu bạn bật xóa tầng bằng cách đánh dấu liên kết sản phẩm khách hàng theo yêu cầu, thì cơ sở dữ liệu sẽ xử lý việc xóa (các) bản ghi con khỏi bảng sản phẩm nhưng nếu bản ghi con này là SpecializedProduct thì hàng liên quan trên SpecializedProduct không bị xóa và do đó ngoại lệ mà bạn đang nhận được. Vì vậy, về cơ bản các mã sau đây sẽ không làm việc:

// 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();  

Mã này sẽ gây EF nộp SQL sau vào cơ sở dữ liệu:

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


Điều đó nói rằng, không có cách nào để cho phép xóa tầng giữa các bảng Product và SpecializedProduct, đó chỉ là cách EF Code First thực hiện một thừa kế TPT và bạn không thể ghi đè nó.

Vì vậy, giải pháp là gì?

Một cách là những gì bạn đã tìm ra, chuyển đổi thủ công các tầng trên giữa các bảng Product và SpecializedProduct để tránh ngoại lệ khi bạn xóa một khách hàng với SpecializedProducts.

Cách thứ hai là để EF chăm sóc các sản phẩm chuyên dụng của khách hàng khi bạn loại bỏ khách hàng.Như tôi đã nói trước đây, điều này xảy ra vì đối tượng khách hàng chưa được tìm nạp đúng cách và EF không có kiến ​​thức về các sản phẩm chuyên biệt của khách hàng, bằng cách tìm nạp đúng đối tượng khách hàng, Ef sẽ bắt đầu theo dõi các liên kết của khách hàng và gửi các câu lệnh SQL cần thiết để đảm bảo rằng tất cả các kỷ lục liên quan được lấy ra trước khi tháo các khách hàng:

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

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

kết quả là, EF sẽ đệ trình các câu lệnh SQL sau vào cơ sở dữ liệu đó một cách hoàn hảo loại bỏ tất cả mọi thứ theo thứ tự:

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

phải mất 13 tháng nhưng Tôi đã nhận được câu trả lời của tôi :-) Cảm ơn! Như tôi nhớ tôi đã kết thúc với việc thực hiện một số sql để tự xác định xóa tầng trên tạo mô hình. –

Các vấn đề liên quan