2013-05-20 22 views
39

Vâng, tôi có một-nhiều mô hình liên quan:Làm thế nào để loại bỏ một đứa trẻ đến nhiều hồ sơ liên quan trong cơ sở dữ liệu mã EF đầu tiên?

public class Parent 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public ICollection<Child> Children { get; set; } 
} 

public class Child 
{ 
    public int Id { get; set; } 
    public string ChildName { get; set; } 
} 

Những gì tôi muốn làm là rõ ràng Parent.Children và loại bỏ các đối tượng trẻ em có liên quan từ cơ sở dữ liệu. Tôi đã cố gắng:

Cơ sở dữ liệu bối cảnh lớp:

modelBuilder.Entity<Parent>() 
      .HasMany(p => p.Children) 
      .WithOptional() 
      .WillCascadeOnDelete(true); 

này hoạt động tốt, nhưng tôi vẫn có hồ sơ dư thừa trong cơ sở dữ liệu với Parent_Id = null lĩnh vực khi tôi làm

parent.Children.Clear(); 
repository.InsertOrUpdate(parent); 

trong tôi lớp kho lưu trữ. Ngoài hành vi tương tự là khi tôi làm:

modelBuilder.Entity<Parent>() 
      .HasMany(pr => pr.Children) 
      .WithOptional(ri => ri.Parent) 
      .WillCascadeOnDelete(true); 

với thêm tài sản Parent trong Child lớp

public class Child 
{ 
    ... 
    public Parent Parent { get; set; } 
    ... 
} 

hoặc khi tôi làm

modelBuilder.Entity<Child>() 
      .HasOptional(p => p.Parent) 
      .WithMany(p => p.Children) 
      .HasForeignKey(p => p.Parent_Id) 
      .WillCascadeOnDelete(true); 

với tài sản PARENT_ID bổ sung trong Child lớp

public class Child 
{ 
    ... 
    public int Parent_Id { get; set; } 
    ... 
} 

Vì vậy, làm thế nào tôi có thể cấu hình xóa tầng một cách chính xác? Hoặc làm thế nào tôi nên loại bỏ các thực thể con? Tôi cho rằng đây là nhiệm vụ bình thường nhưng tôi chỉ thiếu một cái gì đó.

+0

Bạn có thể đăng thêm một số mã không? Có lẽ nội dung đầy đủ của 'OnModelCreating()' của bạn? Khi tôi sao chép và dán các thực thể của bạn và nỗ lực lập bản đồ đầu tiên của bạn (và đặt 'Id' làm thuộc tính khóa cho cả hai thực thể), các lần xóa được xếp tầng chính xác cho tôi. –

Trả lời

37

Cascading xóa không có tác dụng ở đây bởi vì bạn không xóa parent nhưng chỉ cần gọi InsertOrUpdate. Các thủ tục đúng là để xóa các trẻ em một-by-một, như vậy ví dụ:

using (var context = new MyContext()) 
{ 
    var parent = context.Parents.Include(p => p.Children) 
     .SingleOrDefault(p => p.Id == parentId); 

    foreach (var child in parent.Children.ToList()) 
     context.Children.Remove(child); 

    context.SaveChanges(); 
} 
+0

Chắc chắn với việc xóa tầng trên bạn không cần phải xóa riêng từng đứa trẻ? –

+5

@kirsteng: Cascading delete có nghĩa là trẻ em bị xóa ** nếu ** bạn xóa cha mẹ.Nhưng trong câu hỏi này, không có phụ huynh nào bị xóa. Vì vậy, tầng xóa không áp dụng cho kịch bản này. – Slauma

+8

thay vì bỏ qua tất cả các đối tượng "con", chỉ cần nói 'context.Children.RemoveRange (parent.Children.ToArray())' theo cách đó DbContext không phải thực hiện nhiều công việc kiểm tra mỗi lần bạn gọi Remove. Đây có thể không phải là một vấn đề hiệu suất lớn đối với việc xóa, nhưng tôi đã nhận thấy một sự khác biệt lớn khi thêm các mục vào một thời điểm khi tôi thử nghiệm thêm 100k bản ghi bằng cách sử dụng 'context.Children.Add (child)' trong vòng lặp for. – matrixugly

3

Hãy thử thay đổi để

public virtual ICollection<Child> Children { get; set; } 

vì ảo là cần thiết để có được tải lười biếng. như được giải thích here

Tôi nghĩ parent.Children.clear bạn isnt làm việc vì trẻ em chưa được nạp

86

Trong EF6 một cách nhanh hơn để làm các hoạt động là ...

context.Children.RemoveRange(parent.Children) 
+0

Đó là một cách nhanh hơn để viết mã nhưng về hiệu suất, nó có thực sự nhanh hơn không? Nếu tôi muốn xóa tất cả trẻ em dưới dạng cha mẹ với 'parent.Id == 10', và lớp' Child' của tôi có 100 trường và chưa được nạp vào bộ nhớ, có vẻ như không hiệu quả khi sử dụng 'RemoveRange' vì chương trình sẽ có để tải 'parent.Children' với tất cả 100 trường theo mặc định. – VCD

+0

@VCD nó nhanh hơn gọi context.Children.Remove (con) cho mỗi đứa trẻ nhưng không nhanh như chạy sql "DELETE FROM Children, nơi parentId = @ parentId" –

+0

Làm thế nào bạn sẽ đi tìm cha mẹ, nếu chỉ thông tin bạn có là Id con? – guyfromfargo

0

Nếu đối tượng của bạn là tự tham khảo, bạn có thể xóa cả hai trẻ em nhiều đến nhiều và một-nhiều bằng cách sử dụng phương pháp bên dưới. Chỉ cần nhớ gọi db.SaveChanges() sau đó :)

[HttpPost, ActionName("Delete")] 
[ValidateAntiForgeryToken] 
public ActionResult DeleteConfirmed(int id) 
{ 
    Object obj = this.db.Objects.Find(id); 
    this.DeleteObjectAndChildren(obj); 
    this.db.Objects.Remove(obj); 
    this.db.SaveChanges(); 
    return this.Json(new { success = true }); 
} 

/// <summary> 
/// This deletes an object and all children, but does not commit changes to the db. 
/// - MH @ 2016/08/15 14:42 
/// </summary> 
/// <param name="parent"> 
/// The object. 
/// </param> 
private void DeleteObjectAndChildren(Object parent) 
{ 
    // Deletes One-to-Many Children 
    if (parent.Things != null && parent.Things.Count > 0) 
    { 
     this.db.Things.RemoveRange(parent.Things); 
    } 

    // Deletes Self Referenced Children 
    if (parent.Children != null && parent.Children.Count > 0) 
    { 
     foreach (var child in parent.Children) 
     { 
      this.DeleteObjectAndChildren(child); 
     } 

     this.db.Objects.RemoveRange(parent.Children); 
    } 
} 
Các vấn đề liên quan