2014-10-14 21 views
5

Tôi biết nó đã được hỏi trước đó, nhưng sau nhiều giờ tìm kiếm và mã hóa, tôi không thể tiếp cận được với công việc và sạch sẽ. Dưới đây là những gì tôi có:Hoàn thành Chèn/Cập nhật/Xóa các Thực thể Trẻ em trong Khuôn khổ Thực thể

public class QuestionModel 
{ 
    public int QuestionID { get; set; } 
    public string QuestionText { get; set; } 

    public IList<QuestionChoiceModel> Choices { get; set; } 
} 

public class QuestionChoiceModel 
{ 
    public int ChoiceID { get; set; } 
    public string ChoiceText { get; set; } 
} 

Tôi đang sử dụng EF 5 cho ứng dụng ASP.Net MVC này. Generic Repository Pattern và Dependency Injection với Ninject sử dụng InRequestScope() được thiết lập và hoạt động trơn tru. Các mô hình này được ánh xạ tới/từ các thực thể không có vấn đề gì.

Thêm câu hỏi mới vào cơ sở dữ liệu là thẳng về phía trước. Tôi đặt thuộc tính Câu hỏi của một số trường hợp QuestionChoice và EF xử lý phần còn lại.

Sự cố là về cập nhật. Giả sử chúng ta có một câu hỏi trong cơ sở dữ liệu với 3 QuestionChoices:

ChoiceID QuestionID ChoiceText 
-------- ---------- ---------- 
1   1    blah blah 
2   1    blah blah 
3   1    blah blah 

Khi chỉnh sửa trang của một Câu hỏi mở (GET:/câu hỏi/Edit/1), tôi thấy những 3 lựa chọn sử dụng một trong foreach Razor. Tôi đã viết một số mã JQuery có thêm hoặc xóa đánh dấu bắt buộc cho các phần tử đầu vào nếu người dùng muốn. Vì vậy, các QuestionChoice với ID = 1 có thể được chỉnh sửa trên máy khách, ID = 2 có thể bị xóa, và một ID = 4 mới có thể được thêm vào. Dữ liệu biểu mẫu được ràng buộc trở lại một QuestionModel một cách hoàn hảo khi người dùng nhấn nút Save (POST:/Questions/Edit/1). Mô hình được ánh xạ tới thực thể Câu hỏi một cách chính xác. Đó là nơi câu chuyện bắt đầu!

Bây giờ thực thể Câu hỏi có một tập hợp các QuestionChoices một số đã có trong cơ sở dữ liệu, một số nên được thêm vào cơ sở dữ liệu, và một số sẽ bị xóa khỏi cơ sở dữ liệu.

Tôi đã đọc nhiều bài viết như: Entity Framework not saving modified children

tôi có thể xử lý chỉnh sửa ở chỗ cách bẩn. Và cũng có kỷ lục mới bởi:

this._context.Entry(choice).State = EntityState.Added; 

Nhưng tôi đang tìm kiếm một cách thanh lịch hơn. Và cũng có thể xử lý các bản ghi cần xóa. Có cách tiếp cận tốt để xử lý việc chèn/cập nhật/xóa hoàn toàn các thực thể con trong kịch bản này bằng EF? Thành thật mà nói, tôi mong đợi nhiều hơn từ EF.

Trả lời

6

Đây là một vấn đề khó khăn. Thật không may, tôi không thể cung cấp giải pháp mà bạn thích. Tôi không tin điều đó là có thể. EF không thể theo dõi các thay đổi được thực hiện cho các thực thể của bạn trừ khi chúng được thực hiện trong bối cảnh các thực thể được lấy ra - điều này là không thể trong môi trường web. Cách duy nhất để điều này có thể là truy xuất đối tượng Câu hỏi (trong ngữ cảnh) sau POST tới/Câu hỏi/Chỉnh sửa/1 và thực hiện một loại "hợp nhất" giữa Câu hỏi đã đăng và Câu hỏi được truy xuất từ kho dữ liệu. Điều này sẽ bao gồm việc chỉ định các thuộc tính trên QuestionModel và mỗi QuestionChoiceModel được truy xuất từ ​​cơ sở dữ liệu bằng cách sử dụng POST. Tôi sẽ nói rằng đây sẽ không phải là thực hành tuyệt vời, bởi vì bạn S forget quên bao gồm một tài sản. Nó sẽ xảy ra.

Giải pháp tốt nhất (và dễ nhất) tôi có thể cung cấp là thêm/chỉnh sửa QuestionModelQuestionChoiceModel(s) bằng phương pháp .Entry() ở trên. Bạn sẽ hy sinh "thực hành tốt nhất" ở đây cho một giải pháp mà sẽ ít bị lỗi.

QuestionModel questionFromDb; 
QuestionModel questionFromPost; 

QuestionModelChoice[] deletedChoices = questionFromDb.Choices.Where(c => !questionFromPost.Choices.Any(c2 => c2.Id == c.Id)); 


using (var db = new DbContext()) 
{ 
    db.Entry(questionFromPost).State = questionFromPost.Id == 0 ? EntityState.Added : EntityState.Modified; 

    foreach(var choice in questionFromPost.Choices) 
    { 
     db.Entry(choice).State = choice.Id == 0 ? EntityState.Added : EntityState.Modified; 
    } 

    foreach(var deletedChoice in deletedChoices) 
    { 
     db.Entry(deletedChoice).State = EntityState.Deleted; 
    } 

    db.SaveChanges(); 
} 
+0

Cảm ơn. Tôi sẽ nhìn vào nó. –

0

Đây chỉ là bằng chứng về khái niệm.

Controler có func UpdateModel nhưng nó sẽ không làm việc với mô hình phức tạp hơn mà tôi đã bao gồm hồ sơ trẻ em. Tìm kiếm TestUpdate.

Quy tắc số 1: Mỗi bảng đều có cột Id PK.

Quy tắc 2: Mọi FK phải được đặt.

Quy tắc số 3: Cần phải đặt xóa tầng. nếu bạn muốn xóa bản ghi liên quan.

Quy tắc 4: Bản ghi mới cần có Id = 0 hoặc tốt hơn sẽ là Null nhưng Id không thể là rỗng.

public class TestController<T> : Controller where T : class 
{ 
    const string PK = "Id"; 

    protected Models.Entities con; 
    protected System.Data.Entity.DbSet<T> model; 
    public TestController() 
    { 
     con = new Models.Entities(); 
     model = con.Set<T>(); 
    } 

    // GET: Default 
    public virtual ActionResult Index() 
    { 
     ViewBag.Result = TempData["Result"]; 
     TempData["Result"] = null; 

     var list = model.ToList(); 
     return View(list); 
    } 

    [HttpGet] 
    public virtual ActionResult AddEdit(string id) 
    { 
     int nId = 0; 
     int.TryParse(id, out nId); 

     var item = model.Find(nId); 
     return View(item); 

    } 

    [HttpPost] 
    public virtual ActionResult AddEdit(T item) 
    { 
     TestUpdate(item); 

     con.SaveChanges(); 

     return RedirectToAction("Index"); 
    } 

    [HttpGet] 
    public virtual ActionResult Remove(string id) 
    { 
     int nId = 0; 
     int.TryParse(id, out nId); 
     if (nId != 0) 
     { 
      var item = model.Find(nId); 
      con.Entry(item).State = System.Data.Entity.EntityState.Deleted; 
      con.SaveChanges(); 
     } 
     return Redirect(Request.UrlReferrer.ToString()); 
    } 

    private void TestUpdate(object item) 
    { 
     var props = item.GetType().GetProperties(); 
     foreach (var prop in props) 
     { 
      object value = prop.GetValue(item); 
      if (prop.PropertyType.IsInterface && value != null) 
      { 
       foreach (var iItem in (System.Collections.IEnumerable)value) 
       { 
        TestUpdate(iItem); 
       } 
      } 
     } 

     int id = (int)item.GetType().GetProperty(PK).GetValue(item); 
     if (id == 0) 
     { 
      con.Entry(item).State = System.Data.Entity.EntityState.Added; 
     } 
     else 
     { 
      con.Entry(item).State = System.Data.Entity.EntityState.Modified; 
     } 

    } 

} 

Đây là dự án https://github.com/mertuarez/AspMVC_EF/

Bạn cần phải tạo Controler cho mô hình và tạo view cho hành động. Trong trường hợp hành động AddEdit, bạn phải tạo Mẫu trình chỉnh sửa cho các loại phụ.

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