21

Chúng tôi đang sử dụng Mã khung thực thể đầu tiên với các mối quan hệ khóa ngoại. Chúng tôi nghiên cứu cách xử lý việc xóa các đối tượng khỏi một đối tượng ICollection trong ứng dụng của chúng tôi.Có thể xóa con khỏi bộ sưu tập và giải quyết các sự cố trên SaveChang không?

Khi chúng tôi có một thực thể có mối quan hệ trẻ em, chúng tôi có thể thêm các đối tượng trực tiếp vào ICollection của họ bằng cách sử dụng phương thức Thêm. Bây giờ khi bạn sử dụng loại bỏ bạn nhận được lỗi

System.InvalidOperationException xảy ra tin nhắn = Các hoạt động thất bại: Mối quan hệ không thể được thay đổi bởi vì một hoặc nhiều các thuộc tính khóa ngoài là không nullable. Khi thay đổi được thực hiện cho mối quan hệ , thuộc tính khóa ngoài có liên quan được đặt thành giá trị null. Nếu khóa ngoài không hỗ trợ giá trị null, mối quan hệ mới phải được xác định, thuộc tính khóa ngoài phải được gán giá trị không null khác hoặc đối tượng không liên quan phải bị xóa.

Tôi hiểu điều này là vì Xóa trên bộ sưu tập chỉ xóa mối quan hệ bằng cách vô hiệu hóa khóa ngoại. Chúng tôi muốn viết logic kinh doanh của chúng tôi trong thực thể của chúng tôi và cho phép loại bỏ.

Vì vậy, hãy lấy thực thể gốc ra khỏi Repostiory của nó, ví dụ: Order từ OrderRepository sau đó gọi một số phương pháp cụ thể của thực thể, ví dụ: Order.AddOrderline(Orderline orderline) Điều này thêm Dòng đơn hàng vào Đơn đặt hàng virtual ICollection<OrderLine> OrderLines

Tuy nhiên, chúng tôi không thể viết mã như Order.CancelOrderline(int orderLineId) vì chỉ cần xóa khỏi ICollection gây ra lỗi về thay đổi tiết kiệm.

Dường như không có cách nào để đạt được điều này bằng cách thao tác các bộ sưu tập đối tượng. Rõ ràng chúng ta có thể loại bỏ trực tiếp từ Context. Tuy nhiên tôi muốn biến nó thành một phần của thực thể. Chúng ta có thể dọn dẹp một số thực thể không có khoá ngoại trên sự kiện SaveChanges của Entity Framework không? Rõ ràng là cần phải nói cho EF biết những thực thể nào có thể được gỡ bỏ nếu chúng có khóa ngoài rỗng.

Hiện tại chúng tôi đang sử dụng mẫu lưu trữ để trình điều khiển không có quyền truy cập vào ngữ cảnh. Tôi rõ ràng có thể sử dụng một kho lưu trữ OrderLine hoặc loại bỏ một phương thức OrderLine trên kho lưu trữ Order. Tuy nhiên chỉ cần tự hỏi nếu nó có thể viết mã trên thực thể mà không có tham chiếu đến cơ chế kiên trì.

Suy nghĩ? Chúng ta đang đi về điều này tất cả sai? Các ORM khác có cho phép bạn xóa khỏi Bộ sưu tập con không?

Trả lời

38

Tôi không biết đây có phải là giải pháp cho bạn hay không nhưng Entity Framework hỗ trợ Identifying Relationships. Trong mối quan hệ như vậy, khóa ngoại của thực thể con (phụ thuộc) với phụ huynh (chính) phải là một phần của khóa chính (tổng hợp) của thực thể con.Ví dụ - với các chú thích DbContext dữ liệu - các lớp mô hình của bạn phải giống như thế này:

public class Order 
{ 
    [Key] 
    public int OrderId { get; set; } 

    public ICollection<OrderLine> OrderLines { get; set; } 
} 

public class OrderLine 
{ 
    [Key, ForeignKey("Order"), Column(Order = 1)] 
    public int OrderId { get; set; } 

    [Key, Column(Order = 2)] 
    public int OrderLineId { get; set; } 

    public Order Order { get; set; } 
} 

Bạn có thể làm cho OrderLineId một bản sắc autogenerated nếu bạn muốn. Quan trọng là chỉ có FK đến Order là một phần của PK.

Một mã như thế này ví dụ ...

using (var ctx = new MyContext()) 
{ 
    var order = ctx.Orders.Include("OrderLines").Single(o => o.OrderId == 1); 
    var orderLineToDelete = order.OrderLines 
     .FirstOrDefault(ol => ol.OrderLineId == 5); 
    if (orderLineToDelete != null) 
     order.OrderLines.Remove(orderLineToDelete); 

    ctx.SaveChanges(); 
} 

... thực sự sẽ xóa các orderLineToDelete từ cơ sở dữ liệu.

Chi tiết khác là here trong phần "Cân nhắc để xác định và không xác định mối quan hệ".

+0

Vì vậy, nếu tôi tạo khóa tổng hợp trên các thực thể con, EF sẽ giải quyết vấn đề này cho tôi. Bây giờ có vẻ khá hấp dẫn. – GraemeMiller

+6

Điều đó thật tuyệt vời nhưng tôi cần thêm [Key, Column (Order = 0), DatabaseGenerated (DatabaseGeneratedOption.Identity)] int công khai OrderLineId {get; bộ; } để làm cho nó không phàn nàn về chèn danh tính. – GraemeMiller

+0

@GraemeMiller: Đó là ý của tôi với "* Bạn có thể đặt OrderLineId thành nhận dạng tự động nếu bạn muốn *" :) Tôi quên đề cập rằng bạn cần thực hiện việc này trong mô hình * (với DatabaseGeneratedOption) * và * trong kho dữ liệu*. – Slauma

2

Khi bạn đang tìm kiếm, nếu bạn chỉ xóa một Thực thể khỏi bộ sưu tập, Thực thể treo xung quanh được đính kèm với ngữ cảnh đối tượng và cung cấp cho bạn một lỗi khi bạn gọi SaveChanges(); Tôi đã sử dụng các sự kiện miền để kích hoạt một cách gọn gàng để loại bỏ thực thể khỏi ngữ cảnh đối tượng thông qua một kho lưu trữ.

Tôi đã nêu chi tiết phương pháp này trong câu trả lời của mình to this question.

+0

Điều đó trông giống như một cách tiếp cận thực sự thú vị. Nó có tương tự như mẫu lệnh không? Tôi thích khái niệm mô hình hóa các sự kiện miền. Tôi thực sự cần phải đọc xong cuốn sách màu xanh của mình. – GraemeMiller

+1

Hmm ... không thực sự Command, tôi không nghĩ rằng - sự kiện miền là đối tượng không có hành vi mà tín hiệu một cái gì đó đã xảy ra với bất kỳ đối tượng mà xử lý chúng. Tôi nghĩ rằng lần đầu tiên tôi đọc về chúng từ [Martin Fowler] (http://martinfowler.com/eaaDev/DomainEvent.html), nhưng [bài viết này] (http://www.udidahan.com/2009/06/14/ tên miền-sự kiện-cứu rỗi) là một trong đó thực sự giúp tôi hiểu làm thế nào mạnh mẽ họ là :) –

+0

Tuyệt vời mà làm cho tinh thần như họ không có trọng tải như bạn nói. Sẽ đọc về điều đó. Đánh giá cao các tham chiếu bổ sung. – GraemeMiller