2009-11-26 25 views
15

Tôi chỉ tự hỏi làm thế nào mọi người tiếp cận tình huống này. Đó là điều có vẻ giống như một điểm yếu trong việc sử dụng MVC của tôi với ORM (NHibernate trong trường hợp này) ...ASP.NET MVC - Cập nhật một phần mô hình từ góc nhìn

Giả sử bạn có một thực thể tinh vi và phức tạp trong mô hình của mình. Bạn có thể sẽ có một trang quản trị để quản lý các đối tượng thuộc loại này. Nếu thực thể phức tạp, có khả năng bạn sẽ không sửa đổi toàn bộ thực thể trong một biểu mẫu. Bạn vẫn cần chuyển các thuộc tính liên quan đến khung nhìn và kết hợp các thay đổi cho các thuộc tính đó trong mô hình khi khung nhìn trả về chúng.

Ai làm gì trong tình huống này?

  • Tạo mô hình chế độ xem (hoặc chứa) một tập con của thuộc tính thực thể. Chuyển nó đến và từ khung nhìn. Trong phương thức hành động 'chỉnh sửa' trong bộ điều khiển, lấy đối tượng từ kho lưu trữ, mặc dù tất cả các tính năng thích hợp trong ViewModel và áp dụng chúng cho đối tượng Model (model.a = viewmodel.a, modelb = viewmodel.b). Điều này có vẻ là con đường hợp lý rõ ràng, nhưng tạo ra rất nhiều mã nước tẻ nhạt. Điều này cũng phức tạp xác nhận một chút.

  • Cái gì khác?

Tôi đã xem xét ngắn gọn về bản đồ hóa - nhưng điều này dường như không phù hợp với hóa đơn chính xác, có thể tôi sai?

Cảm ơn.

+0

tôi sử dụng một mô hình xem và bạn là hoàn toàn đúng nó dẫn đến một số bàn tay trái đang tay phải nhàm chán. Từ những gì tôi đã thu thập AutoMapper làm giảm bớt một số mã đó. – Aaron

+0

Vâng, tôi có cảm giác rằng đây là con đường của nó. Bạn không bao giờ biết, ai đó có thể có một số thủ thuật khéo léo mặc dù ... – UpTheCreek

Trả lời

11

Điều này nghe giống như kịch bản hoàn hảo cho tự động hóa. Bạn tạo một lớp mô hình khung nhìn có chứa một tập con của các trường hoặc mô hình thực của bạn và bạn để cho AutoMapper xử lý các giá trị extraccting từ đối tượng mô hình miền vào đối tượng mô hình khung nhìn của bạn. Bạn đang gặp phải vấn đề gì với phương pháp này?

Hãy xem xét ví dụ sau:

Đây là mô hình tên miền của bạn và mô hình quan điểm của bạn

public class Person 
{ 
    public string FirstName 
    { get; set; } 

    public string LastName 
    { get; set; } 

    public string HomeNumber 
    { get; set; } 

    public string Address1 
    { get; set; } 

    public string Address2 
    { get; set; } 
} 

public class PersonViewModel 
{ 
    public string FirstName 
    { get; set; } 

    public string LastName 
    { get; set; } 

    public string HomeNumber 
    { get; set; } 
} 

Dưới đây là bản đồ của bạn, bạn phải tạo một ánh xạ theo cả hai hướng từ dm-> vm và vm-> dm.

Từ những gì tôi thấy khi sử dụng Automapper là nếu bạn ánh xạ từ đối tượng A đến B và B có thuộc tính A không có, nó sẽ được đặt lại. Vì vậy, khi tôi tạo bản đồ tôi chỉ đạo nó để bỏ qua những thuộc tính còn thiếu. Tôi không phải là chuyên gia Automapper nên tôi có thể sử dụng sai.

Mapping

Mapper.CreateMap<Person, PersonViewModel>(); 
// Automapper will reset values in dest which don't exist in source, so be sure to ignore them! 
Mapper.CreateMap<PersonViewModel, Person>() 
    .ForMember(dest => dest.HomeNumber, opt => opt.Ignore()); 

Cuối cùng sử dụng:

Person p = new Person() 
{ 
    FirstName = "First", 
    LastName = "Last", 
    Address1 = "add 1", 
    Address2 = "add 2" 
}; 

PersonViewModel pvm = Mapper.Map<Person, PersonViewModel>(p); 
// Map to a new person 
Person p2 = Mapper.Map<PersonViewModel, Person>(pvm); 

// Map to the existing person just to update it 
Person p3 = new Person() 
{ 
    HomeNumber = "numberHere" 
}; 

// This will update p3 
Mapper.Map<PersonViewModel, Person>(pvm, p3); 

Bởi vì loại trừ, điều này rõ ràng là ít hơn lý tưởng, nhưng tốt hơn nhiều so với tay làm toàn bộ điều.

+0

Cảm ơn Nói, điều này là tốt cho các tình huống 'chỉ xem'. Nhưng như tôi hiểu nó automapper là không thể ánh xạ trở lại đối tượng mô hình miền cho giá trị chỉnh sửa từ xem (ví dụ trong một 'chỉnh sửa' hình thức quản trị tình hình). Có lẽ tôi đã sai lầm? – UpTheCreek

+0

Tôi vừa thêm một ví dụ ở đây cho bạn. –

+0

Cảm ơn các ví dụ chi tiết, có vẻ như có nhiều thứ tự động hơn tôi đã nhận ra. Tôi sẽ nghiên cứu thêm một chút. – UpTheCreek

1

Điều gì sẽ xảy ra nếu bạn có mô hình đầy đủ nhưng mỗi trang chỉ sử dụng và cập nhật phần bắt buộc? Sau đó, bạn cập nhật mô hình kinh doanh bằng cách sử dụng dữ liệu chế độ xem hoàn chỉnh ở trang cuối cùng.

+0

Cảm ơn. Tôi nghĩ rằng bạn đang đề xuất một số loại hình thức phong cách 'wizard' đa? Tôi không thực sự nói về những tình huống mà tôi phải cập nhật toàn bộ mô hình theo những phần nhỏ hơn, mà chỉ là các chi tiết của việc chuyển một mô hình để cập nhật. – UpTheCreek

+0

Không, tôi không nghĩ là anh ấy. Tôi nghĩ anh ta đề nghị không nên sử dụng một viewmodel. Đơn giản chỉ cần vượt qua mô hình hoàn chỉnh và có hành động chỉ thay đổi/cập nhật các thuộc tính mà bạn cần. Đơn giản hóa quá trình bằng cách loại bỏ đường ống dẫn phụ bổ sung của đối tượng VM. –

+0

Vì vậy, điều gì về bit 'cập nhật mô hình kinh doanh bằng cách sử dụng * dữ liệu xem hoàn chỉnh ở trang cuối cùng *' sau đó? – UpTheCreek

1

y, viewmodel + automapper.

ps. một mô hình phức tạp, có xu hướng ... làm phức tạp mọi thứ - liệu nó có thực sự đáng giá trong kịch bản của bạn không?

2

Tại sao bạn không sử dụng TryUpdateModel với bộ sưu tập biểu mẫu.

Nếu xem bạn đang chỉnh sửa một người

public class Person 
{ 
    public string ID { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Email { get; set; } 
    public string Address { get; set; } 
} 

Và tầm nhìn của bạn chỉ được chỉnh sửa tên đầu tiên và tên cuối cùng, bạn có thể làm điều này:

public ActionResult Action(FormCollection form) 
{ 
    Person personToUpdate = Repository.GetPerson(form["ID"]); 

    TryUpdateModel<Person>(personToUpdate, form); 

    Repository.Update(personToUpdate) 

    return View(); 
} 

Điều đó sẽ chỉ cập nhật Person với các mục đó là một phần của bộ sưu tập biểu mẫu. Nếu bạn không muốn một trường được cập nhật, đừng gửi nó với biểu mẫu.

+0

Tôi nói không chắc chắn và rất thích nhận được một số phản hồi. Tôi nghĩ rằng bạn không muốn làm điều này bởi vì 1. Nó ít gõ mạnh mẽ, 2. nó không thể được kết hợp với một chất kết dính mô hình tùy chỉnh. Levi đã giải thích một nơi nào đó rằng updatemodel chỉ được dùng để cập nhật viewmodel. – Martin

0

Ngay bây giờ Tôi đang làm việc trên một dự án lớn sử dụng kiến ​​trúc S # arp và im cũng sử dụng phương pháp:

Model -> ViewModel -> Model 

tôi sử dụng các ViewModel cho phần Binding và validations, cách tiếp cận khác là sử dụng Mô hình trực tiếp (với tryUpdateModel/UpdateModel mà chúng tôi đã sử dụng trong quá trình phát triển mẫu thử nghiệm) nhưng đối với các kịch bản phức tạp, chúng tôi sẽ xử lý các tình huống đặc biệt như SelectLists/Checkbox/Projections/HMAC Validations trong một ViewModel nhỏ và sử dụng rất nhiều Request.Form [" key "] = (, nhược điểm khác là xử lý các tình huống lỗi mà bạn muốn repopulate biểu mẫu với đầu vào của người dùng, tôi thấy nó phức tạp hơn một chút bằng cách sử dụng Model trực tiếp (sử dụng một ViewModel w e mất rất nhiều lợi thế của ModelState cố gắng giá trị, tiết kiệm cho chúng tôi một vài chuyến đi đến DB, bất cứ ai đã phải đối mặt với kịch bản này sẽ biết những gì tôi có ý nghĩa).

Cách tiếp cận này tốn một chút thời gian, giống như bạn đã nói, bạn kết thúc các thuộc tính phù hợp, nhưng theo ý kiến ​​của tôi là cách để đi cho các biểu mẫu phức tạp.

Điều đáng nói là chúng tôi chỉ sử dụng ViewModels cho các kịch bản Tạo/Chỉnh sửa, cho hầu như mọi thứ khác mà chúng tôi sử dụng trực tiếp cho mô hình.

Tôi chưa sử dụng tự động cho đến giờ, nhưng chắc chắn tôi sẽ thử.

1

Tôi sử dụng cách tiếp cận tương tự với đối tượng của bạn (Entity -> ViewModel -> Xem nhưng chỉ trên chế độ xem với các thực thể "phức tạp" có mối quan hệ 1: M hoặc M: M. Trong hầu hết các trường hợp, tôi đi theo con đường thấp và đi đến Entity-> Xem khi tôi có một thực thể đơn giản.

My ViewModel được định nghĩa là thuộc tính hỗ trợ Entity +: SelectList hoặc MultiSelectListstring hoặc List<string>. Tôi cũng sẽ sử dụng một ViewModel cho các trường hợp mà tôi có các thuộc tính mà tôi cần cho khung nhìn nhưng có thể không nhất thiết cần trong thực thể (cơ sở dữ liệu).

Http Nhận các phương thức điều khiển rất đơn giản Hành độngĐược thực hiện với return View(repository.FetchNewViewModel()) để tạo hoặc repository.FetchModelById(id) cho Chỉnh sửa. Trong cả hai trường hợp, tôi đang khởi tạo các thực thể của mình trước khi chuyển chúng sang khung nhìn.

Create([Bind(Exclude = "Entity.EntityId")] ViewModel model)Edit(ViewModel model) là các phương pháp của Trình điều khiển bài đăng của Tạo và chỉnh sửa. Chế độ xem Chỉnh sửa của tôi có trường nhập ẩn cho EntityId để chuyển qua lại.

Vào thời điểm phương thức Http Post có chế độ xem mô hình, tôi mất tất cả các giá trị Entity.Relation và ViewModel. Tôi phải xây dựng lại các đối tượng nếu tôi muốn quan điểm của tôi để hiển thị đúng: '

try 
{ 
    var tags = model.TagIds; // List<string> or <int> depending on your Id type 
    if (model.TagsList == null) // It will be 
    { 
     model.TagsList = _repository.FetchSelectedTags(tags); // Build a new SelectList 
    } 

    if (!ModelState.IsValid) 
    { 
     return View(model); 
    } 

    _repository.Add(model.Article, tags); // or Save() for Edit 
} 
catch 
{ 
    return View(model); // Generally means something screwed in the repository class 
} 

return RedirectToAction("Index"); 

'

Có lẽ 30% cơ sở thực thể của tôi sử dụng một ViewModel vì vậy tôi chắc chắn chỉ sử dụng nó khi cần thiết. Nếu bạn có các khung nhìn phức tạp và dữ liệu mô hình trong hầu hết các trường hợp, bạn có thể chia nhỏ nó thành các khung nhìn nhỏ hơn.

5
  1. Để mô hình chế độ xem của bạn trực tiếp với mô hình miền của bạn.

  2. Chỉ định Model làm đối số cho số routeValues như bên dưới. Điều này có nghĩa là mô hình khung nhìn của bạn sẽ được khởi tạo với các giá trị từ mô hình miền. Chỉ tập hợp con các trường trong biểu mẫu sẽ bị ghi đè trong kết quả personViewData.

Cập nhật Xem:

@model ViewModel.PersonView 

@using (Html.BeginForm("Update", "Profile", Model, FormMethod.Post)) 
{ 
    ...Put your sub set of the PersonView fields here 
} 

ProfileController:

public ActionResult Update(string userName) 
{ 
    Person person = _unitOfWork.Person.Get().Where(p => p.UserName == userName).FirstOrDefault(); 
    PersonView personView = new PersonView(); 
    Mapper.Map(person, personView); 

    return View(personView); 
} 

[HttpPost] 
public ActionResult Update(PersonView personViewData) 
{ 
    Person person = _unitOfWork.Person.Get().Where(p => p.UserName == personViewData.UserName).FirstOrDefault(); 
    Mapper.Map(personViewData, person); 
    _unitOfWork.Person.Update(person); 
    _unitOfWork.Save(); 

    return Json(new { saved = true, status = "" }); 
} 
Các vấn đề liên quan