ฉันใหม่กับ ASP.NET MVC ฉันมีปัญหาในการทำความเข้าใจกับวัตถุประสงค์ของ ViewModel
ViewModel คืออะไรและทำไมเราต้องใช้ ViewModel สำหรับแอพพลิเคชั่น ASP.NET MVC
ถ้าฉันได้รับตัวอย่างที่ดีเกี่ยวกับการทำงานและคำอธิบายที่จะดีกว่า
ฉันใหม่กับ ASP.NET MVC ฉันมีปัญหาในการทำความเข้าใจกับวัตถุประสงค์ของ ViewModel
ViewModel คืออะไรและทำไมเราต้องใช้ ViewModel สำหรับแอพพลิเคชั่น ASP.NET MVC
ถ้าฉันได้รับตัวอย่างที่ดีเกี่ยวกับการทำงานและคำอธิบายที่จะดีกว่า
คำตอบ:
A view model
แสดงข้อมูลที่คุณต้องการแสดงในมุมมอง / หน้าไม่ว่าจะใช้สำหรับข้อความแบบคงที่หรือสำหรับค่าอินพุต (เช่นกล่องข้อความและรายการแบบเลื่อนลง) ที่สามารถเพิ่มลงในฐานข้อมูล (หรือแก้ไข) domain model
มันเป็นสิ่งที่แตกต่างจากของคุณ มันเป็นแบบจำลองสำหรับการดู
ให้เราบอกว่าคุณมีEmployee
คลาสที่แสดงถึงรูปแบบโดเมนพนักงานของคุณและมีคุณสมบัติดังต่อไปนี้ (ตัวระบุที่ไม่ซ้ำกันชื่อนามสกุลและวันที่สร้าง):
public class Employee : IEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateCreated { get; set; }
}
มุมมองแบบจำลองแตกต่างจากแบบจำลองโดเมนในมุมมองแบบจำลองนั้นมีเฉพาะข้อมูล (แสดงโดยคุณสมบัติ) ที่คุณต้องการใช้กับมุมมองของคุณ ตัวอย่างเช่นสมมติว่าคุณต้องการเพิ่มระเบียนพนักงานใหม่โมเดลมุมมองของคุณอาจมีลักษณะเช่นนี้:
public class CreateEmployeeViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
อย่างที่คุณเห็นมันมีเพียงสองคุณสมบัติเท่านั้น คุณสมบัติทั้งสองนี้ยังอยู่ในรูปแบบโดเมนพนักงาน ทำไมคุณถึงถามอย่างนี้ Id
อาจไม่ได้ตั้งค่าจากมุมมองมันอาจถูกสร้างขึ้นโดยอัตโนมัติโดยตารางพนักงาน และDateCreated
อาจถูกตั้งค่าในขั้นตอนการจัดเก็บหรือในชั้นบริการของแอปพลิเคชันของคุณ ดังนั้นId
และDateCreated
ไม่จำเป็นในโมเดลการดู คุณอาจต้องการแสดงคุณสมบัติทั้งสองนี้เมื่อคุณดูรายละเอียดของพนักงาน (พนักงานที่ถูกบันทึกไว้แล้ว) เป็นข้อความคงที่
เมื่อโหลดมุมมอง / หน้าวิธีสร้างการกระทำในตัวควบคุมพนักงานของคุณจะสร้างอินสแตนซ์ของโมเดลมุมมองนี้เติมฟิลด์ใด ๆ หากต้องการจากนั้นส่งโมเดลมุมมองนี้ไปยังมุมมอง / หน้า:
public class EmployeeController : Controller
{
private readonly IEmployeeService employeeService;
public EmployeeController(IEmployeeService employeeService)
{
this.employeeService = employeeService;
}
public ActionResult Create()
{
CreateEmployeeViewModel model = new CreateEmployeeViewModel();
return View(model);
}
public ActionResult Create(CreateEmployeeViewModel model)
{
// Do what ever needs to be done before adding the employee to the database
}
}
มุมมอง / หน้าของคุณอาจมีลักษณะเช่นนี้ (สมมติว่าคุณกำลังใช้ASP.NET MVC
และRazor
เครื่องมือดู):
@model MyProject.Web.ViewModels.CreateEmployeeViewModel
<table>
<tr>
<td><b>First Name:</b></td>
<td>@Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" })
@Html.ValidationMessageFor(m => m.FirstName)
</td>
</tr>
<tr>
<td><b>Last Name:</b></td>
<td>@Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" })
@Html.ValidationMessageFor(m => m.LastName)
</td>
</tr>
</table>
การตรวจสอบจึงจะกระทำในวันที่FirstName
และLastName
เวลาเท่านั้น ใช้FluentValidationคุณอาจมีการตรวจสอบเช่นนี้
public class CreateEmployeeViewModelValidator : AbstractValidator<CreateEmployeeViewModel>
{
public CreateEmployeeViewModelValidator()
{
RuleFor(m => m.FirstName)
.NotEmpty()
.WithMessage("First name required")
.Length(1, 50)
.WithMessage("First name must not be greater than 50 characters");
RuleFor(m => m.LastName)
.NotEmpty()
.WithMessage("Last name required")
.Length(1, 50)
.WithMessage("Last name must not be greater than 50 characters");
}
}
และด้วยคำอธิบายประกอบข้อมูลอาจมีลักษณะเช่นนี้:
public class CreateEmployeeViewModel : ViewModelBase
{
[Display(Name = "First Name")]
[Required(ErrorMessage = "First name required")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
[Required(ErrorMessage = "Last name required")]
public string LastName { get; set; }
}
สิ่งสำคัญที่ต้องจำคือโมเดลมุมมองแสดงข้อมูลที่คุณต้องการใช้เท่านั้นเท่านั้นไม่มีอะไรอื่น คุณสามารถจินตนาการรหัสและการตรวจสอบที่ไม่จำเป็นทั้งหมดได้หากคุณมีรูปแบบโดเมนที่มีคุณสมบัติ 30 รายการและคุณต้องการอัปเดตค่าเดียว รับสถานการณ์นี้คุณจะมีเพียงหนึ่งค่า / ทรัพย์สินนี้ในรูปแบบมุมมองและไม่ใช่คุณสมบัติทั้งหมดที่อยู่ในวัตถุโดเมน
มุมมองแบบจำลองอาจมีเพียงข้อมูลจากตารางฐานข้อมูลเดียว มันสามารถรวมข้อมูลจากตารางอื่น ยกตัวอย่างข้างต้นเกี่ยวกับการเพิ่มบันทึกพนักงานใหม่ นอกเหนือจากการเพิ่มชื่อและนามสกุลที่คุณอาจต้องการเพิ่มแผนกของพนักงาน รายการแผนกนี้จะมาจากDepartments
โต๊ะของคุณ ดังนั้นตอนนี้คุณมีข้อมูลจากEmployees
และDepartments
ตารางในรูปแบบมุมมองเดียว จากนั้นคุณจะต้องเพิ่มคุณสมบัติสองประการต่อไปนี้ในโมเดลมุมมองของคุณและเติมด้วยข้อมูล:
public int DepartmentId { get; set; }
public IEnumerable<Department> Departments { get; set; }
เมื่อแก้ไขข้อมูลพนักงาน (พนักงานที่ถูกเพิ่มไปยังฐานข้อมูลแล้ว) จะไม่แตกต่างจากตัวอย่างด้านบนของฉันมากนัก EditEmployeeViewModel
สร้างรูปแบบมุมมองที่เรียกว่ายกตัวอย่างเช่น มีข้อมูลที่คุณต้องการแก้ไขในโมเดลมุมมองนี้เท่านั้นเช่นชื่อและนามสกุล แก้ไขข้อมูลและคลิกปุ่มส่ง ฉันจะไม่กังวลมากเกินไปเกี่ยวกับId
ฟิลด์เนื่องจากId
ค่าอาจจะอยู่ใน URL ตัวอย่างเช่น:
http://www.yourwebsite.com/Employee/Edit/3
ใช้สิ่งนี้Id
และส่งผ่านไปยังเลเยอร์ที่เก็บข้อมูลของคุณพร้อมกับชื่อและค่านามสกุล
เมื่อลบบันทึกฉันมักจะทำตามเส้นทางเดียวกันกับรุ่นมุมมองแก้ไข ฉันก็จะมี URL เช่น:
http://www.yourwebsite.com/Employee/Delete/3
เมื่อมุมมองโหลดขึ้นเป็นครั้งแรกฉันจะได้รับข้อมูลของพนักงานจากฐานข้อมูลโดยใช้Id
3 ฉันจะแสดงข้อความคงที่ในมุมมอง / หน้าของฉันเพื่อให้ผู้ใช้สามารถเห็นพนักงานที่ถูกลบ เมื่อผู้ใช้คลิกปุ่มลบฉันจะใช้Id
ค่า 3 แล้วส่งไปยังที่เก็บเลเยอร์ของฉัน คุณต้องการเพียงId
จะลบบันทึกจากตาราง
อีกจุดหนึ่งคุณไม่จำเป็นต้องใช้โมเดลการดูสำหรับทุกการกระทำ ถ้ามันเป็นข้อมูลที่เรียบง่ายมันก็น่าจะใช้ได้ดีEmployeeViewModel
ถ้ามันเป็นข้อมูลง่ายแล้วมันจะดีกับการใช้งานเท่านั้นหากเป็นมุมมอง / หน้าเว็บที่ซับซ้อนและแตกต่างจากกันฉันแนะนำให้คุณใช้โมเดลมุมมองแยกต่างหากสำหรับแต่ละมุมมอง
ฉันหวังว่าสิ่งนี้จะเป็นการขจัดความสับสนที่คุณมีเกี่ยวกับแบบจำลองการดูและแบบจำลองโดเมน
มุมมองแบบจำลองเป็นคลาสที่แสดงถึงตัวแบบข้อมูลที่ใช้ในมุมมองเฉพาะ เราสามารถใช้คลาสนี้เป็นแบบจำลองสำหรับหน้าเข้าสู่ระบบ:
public class LoginPageVM
{
[Required(ErrorMessage = "Are you really trying to login without entering username?")]
[DisplayName("Username/e-mail")]
public string UserName { get; set; }
[Required(ErrorMessage = "Please enter password:)")]
[DisplayName("Password")]
public string Password { get; set; }
[DisplayName("Stay logged in when browser is closed")]
public bool RememberMe { get; set; }
}
การใช้โมเดลมุมมองนี้คุณสามารถกำหนดมุมมอง (Razor view engine):
@model CamelTrap.Models.ViewModels.LoginPageVM
@using (Html.BeginForm()) {
@Html.EditorFor(m => m);
<input type="submit" value="Save" class="submit" />
}
และการกระทำ:
[HttpGet]
public ActionResult LoginPage()
{
return View();
}
[HttpPost]
public ActionResult LoginPage(LoginPageVM model)
{
...code to login user to application...
return View(model);
}
ซึ่งก่อให้เกิดผลลัพธ์นี้ (หน้าจอจะดำเนินการหลังจากส่งแบบฟอร์มพร้อมข้อความยืนยัน):
อย่างที่คุณเห็นโมเดลมุมมองมีหลายบทบาท:
LabelFor
, EditorFor
,DisplayFor
ผู้ช่วย)อีกตัวอย่างของโมเดลการดูและการดึงข้อมูล: เราต้องการแสดงข้อมูลผู้ใช้พื้นฐานสิทธิ์ของเขาและชื่อผู้ใช้ เราสร้างโมเดลมุมมองพิเศษซึ่งมีเฉพาะฟิลด์ที่จำเป็น เราดึงข้อมูลจากเอนทิตีต่าง ๆ จากฐานข้อมูล แต่มุมมองนั้นรับรู้เฉพาะคลาสโมเดลมุมมอง:
public class UserVM {
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsAdministrator { get; set; }
public string MothersName { get; set; }
}
การสืบค้น:
var user = db.userRepository.GetUser(id);
var model = new UserVM() {
ID = user.ID,
FirstName = user.FirstName,
LastName = user.LastName,
IsAdministrator = user.Proviledges.IsAdministrator,
MothersName = user.Mother.FirstName + " " + user.Mother.LastName
}
แก้ไข: ฉันอัปเดตคำตอบนี้ในบล็อกของฉัน:
http://www.samwheat.com/post/The-function-of-ViewModels-in-MVC-web-development
คำตอบของฉันค่อนข้างยาว แต่ฉันคิดว่ามันสำคัญที่จะต้องเปรียบเทียบมุมมองแบบจำลองกับรุ่นที่ใช้กันทั่วไปประเภทอื่นเพื่อเข้าใจว่าทำไมถึงแตกต่างกันและทำไมจึงจำเป็น
เพื่อสรุปและตอบคำถามที่ถูกถามโดยตรง:
โดยทั่วไปแล้วโมเดลการดูเป็นวัตถุที่มีคุณสมบัติและวิธีการทั้งหมดที่จำเป็นในการแสดงผลมุมมอง ดูคุณสมบัติของโมเดลมักจะเกี่ยวข้องกับวัตถุข้อมูลเช่นลูกค้าและคำสั่งซื้อและนอกจากนี้ยังมีคุณสมบัติที่เกี่ยวข้องกับหน้าหรือแอปพลิเคชันของตัวเองเช่นชื่อผู้ใช้ชื่อแอปพลิเคชันเป็นต้นดูรุ่นให้วัตถุที่สะดวกในการส่ง สร้างหน้า html หนึ่งในหลาย ๆ เหตุผลในการใช้โมเดลมุมมองคือโมเดลวิวจัดให้มีวิธีทดสอบหน่วยงานการนำเสนอบางอย่างเช่นการจัดการอินพุตผู้ใช้การตรวจสอบข้อมูลการดึงข้อมูลเพื่อแสดงผลเป็นต้น
นี่คือการเปรียบเทียบโมเดล Entity (โมเดล a.ka. a.ka. ของ DTO), โมเดลการนำเสนอและดูโมเดล
การถ่ายโอนข้อมูลวัตถุ aka“ แบบจำลอง”
Data Transfer Object (DTO) เป็นคลาสที่มีคุณสมบัติที่ตรงกับ schema ของตารางในฐานข้อมูล DTO มีชื่อสำหรับการใช้งานทั่วไปสำหรับการส่งข้อมูลไปยังและจากแหล่งข้อมูล
ลักษณะของ DTO:
•วัตถุทางธุรกิจ - คำจำกัดความของพวกเขาขึ้นอยู่กับข้อมูลแอปพลิเคชัน
•มักจะมีคุณสมบัติเท่านั้น - ไม่มีรหัส
•ใช้เป็นหลักสำหรับการขนส่งข้อมูลไปยังและจากฐานข้อมูล
•คุณสมบัติตรงหรือตรงกับเขตข้อมูลในตารางเฉพาะในแหล่งข้อมูล
ตารางฐานข้อมูลมักจะถูกทำให้เป็นมาตรฐานดังนั้น DTO ก็จะถูกทำให้เป็นมาตรฐานด้วยเช่นกัน สิ่งนี้ทำให้มีการใช้งานที่ จำกัด ในการนำเสนอข้อมูล อย่างไรก็ตามสำหรับโครงสร้างข้อมูลอย่างง่ายพวกเขามักจะทำได้ค่อนข้างดี
ต่อไปนี้เป็นสองตัวอย่างของสิ่งที่ DTO อาจมีลักษณะ:
public class Customer
{
public int ID { get; set; }
public string CustomerName { get; set; }
}
public class Order
{
public int ID { get; set; }
public int CustomerID { get; set; }
public DateTime OrderDate { get; set; }
public Decimal OrderAmount { get; set; }
}
รูปแบบการนำเสนอ
รูปแบบการนำเสนอเป็นเครื่องมือคลาสที่ใช้ในการแสดงข้อมูลบนหน้าจอหรือรายงาน โดยทั่วไปแล้วตัวแบบการนำเสนอมักใช้เพื่อจำลองโครงสร้างข้อมูลที่ซับซ้อนซึ่งประกอบด้วยข้อมูลจาก DTO หลาย ๆ ตัว รูปแบบการนำเสนอมักแสดงถึงมุมมองข้อมูลที่ผิดปกติ
ลักษณะของแบบจำลองการนำเสนอ:
•วัตถุทางธุรกิจ - คำจำกัดความของพวกเขาขึ้นอยู่กับข้อมูลแอปพลิเคชัน
•มีคุณสมบัติส่วนใหญ่ โดยทั่วไปรหัสจะ จำกัด อยู่ที่การจัดรูปแบบข้อมูลหรือแปลงเป็นหรือจาก DTO รูปแบบการนำเสนอไม่ควรมีตรรกะทางธุรกิจ
•มักจะนำเสนอมุมมองข้อมูลที่ผิดปกติ นั่นคือพวกเขามักจะรวมคุณสมบัติจากหลาย DTO ของ
•มักจะมีคุณสมบัติของประเภทฐานที่แตกต่างจาก DTO ตัวอย่างเช่นจำนวนเงินดอลลาร์อาจแสดงเป็นสตริงเพื่อให้สามารถมีเครื่องหมายจุลภาคและสัญลักษณ์สกุลเงิน
•มักถูกกำหนดโดยวิธีการใช้งานรวมถึงคุณสมบัติของวัตถุ กล่าวอีกนัยหนึ่ง DTO แบบง่าย ๆ ที่ใช้เป็นโมเดลการสำรองสำหรับการเรนเดอร์กริดนั้นอันที่จริงแล้วยังเป็นโมเดลการนำเสนอในบริบทของกริดนั้น
รูปแบบการนำเสนอจะใช้“ ตามต้องการ” และ“ ในกรณีที่จำเป็น” (ในขณะที่ DTO มักเชื่อมโยงกับสคีมาฐานข้อมูล) รูปแบบการนำเสนออาจถูกใช้เพื่อสร้างแบบจำลองข้อมูลสำหรับทั้งหน้ากริดบนหน้าหรือแบบเลื่อนลงบนกริดบนหน้า รูปแบบการนำเสนอมักจะมีคุณสมบัติที่เป็นรูปแบบการนำเสนออื่น ๆ รูปแบบการนำเสนอมักถูกสร้างขึ้นเพื่อจุดประสงค์ในการใช้งานครั้งเดียวเช่นเพื่อแสดงกริดเฉพาะในหน้าเดียว
ตัวอย่างรูปแบบการนำเสนอ:
public class PresentationOrder
{
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
public string CustomerName { get; set; }
public Decimal OrderAmount { get; set; }
public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}
ดูแบบจำลอง
โมเดลมุมมองนั้นคล้ายคลึงกับโมเดลการนำเสนอซึ่งเป็นคลาสสำรองสำหรับการเรนเดอร์มุมมอง อย่างไรก็ตามมันแตกต่างจาก Presentation Model หรือ DTO มากในเรื่องการสร้าง ดูแบบจำลองมักจะมีคุณสมบัติเช่นเดียวกับแบบจำลองการนำเสนอและ DTO และด้วยเหตุนี้พวกเขามักจะสับสนแบบหนึ่งสำหรับแบบอื่น
ลักษณะของรูปแบบการดู:
•เป็นแหล่งข้อมูลเดียวที่ใช้ในการแสดงหน้าหรือหน้าจอ โดยทั่วไปนี่หมายความว่าโมเดลการดูจะแสดงคุณสมบัติทุกอย่างที่ตัวควบคุมใด ๆ ในหน้านั้นจำเป็นต้องแสดงอย่างถูกต้อง การทำให้แบบจำลองมุมมองเป็นแหล่งข้อมูลเดียวสำหรับมุมมองช่วยเพิ่มความสามารถและความคุ้มค่าสำหรับการทดสอบหน่วยอย่างมาก
•เป็นวัตถุคอมโพสิตที่มีคุณสมบัติที่ประกอบด้วยข้อมูลแอปพลิเคชันรวมถึงคุณสมบัติที่ใช้โดยรหัสแอปพลิเคชัน คุณลักษณะนี้มีความสำคัญเมื่อออกแบบโมเดลมุมมองสำหรับการใช้ซ้ำและอธิบายไว้ในตัวอย่างด้านล่าง
•มีรหัสแอปพลิเคชัน ดูแบบจำลองมักจะมีวิธีการที่เรียกในระหว่างการแสดงผลและเมื่อผู้ใช้โต้ตอบกับหน้า รหัสนี้มักเกี่ยวข้องกับการจัดการเหตุการณ์ภาพเคลื่อนไหวการมองเห็นการควบคุมการใส่สไตล์ ฯลฯ
•มีรหัสที่เรียกใช้บริการทางธุรกิจเพื่อดึงข้อมูลหรือส่งไปยังเซิร์ฟเวอร์ฐานข้อมูล รหัสนี้มักจะวางผิดพลาดในตัวควบคุม การเรียกบริการธุรกิจจากคอนโทรลเลอร์มักจะ จำกัด ประโยชน์ของรูปแบบการดูสำหรับการทดสอบหน่วย เพื่อให้ชัดเจนมุมมองตัวเองไม่ควรมีตรรกะทางธุรกิจ แต่ควรโทรไปยังบริการที่มีตรรกะทางธุรกิจ
•มักจะมีคุณสมบัติที่เป็นรุ่นมุมมองอื่น ๆ สำหรับหน้าหรือหน้าจออื่น ๆ
•เขียน“ ต่อหน้า” หรือ“ ต่อหน้า” โดยทั่วไปรูปแบบการดูที่ไม่ซ้ำกันจะเขียนขึ้นสำหรับทุกหน้าหรือหน้าจอในแอปพลิเคชัน
•มักจะได้รับมาจากคลาสฐานเนื่องจากหน้าและหน้าจอส่วนใหญ่ใช้คุณสมบัติทั่วไป
ดูองค์ประกอบของแบบจำลอง
ตามที่ระบุไว้ก่อนหน้านี้มุมมองแบบจำลองเป็นวัตถุประกอบที่รวมคุณสมบัติของแอปพลิเคชันและคุณสมบัติข้อมูลธุรกิจไว้ในวัตถุเดียว ตัวอย่างของคุณสมบัติแอปพลิเคชันที่ใช้กันทั่วไปที่ใช้กับโมเดลมุมมองคือ:
•คุณสมบัติที่ใช้แสดงสถานะแอปพลิเคชันเช่นข้อความแสดงข้อผิดพลาดชื่อผู้ใช้สถานะ ฯลฯ
•คุณสมบัติที่ใช้ในการฟอร์แมต, แสดง, จัดทรงหรือควบคุมการเคลื่อนไหว
•คุณสมบัติที่ใช้สำหรับการผูกข้อมูลเช่นรายการวัตถุและคุณสมบัติที่เก็บข้อมูลระดับกลางที่ป้อนโดยผู้ใช้
ตัวอย่างต่อไปนี้แสดงให้เห็นว่าทำไมธรรมชาติของรูปแบบประกอบที่มีความสำคัญและวิธีที่เราสามารถสร้างรูปแบบการดูที่มีประสิทธิภาพและนำกลับมาใช้ใหม่ได้ดีที่สุด
สมมติว่าเรากำลังเขียนเว็บแอปพลิเคชัน หนึ่งในข้อกำหนดของการออกแบบแอปพลิเคชันคือต้องแสดงชื่อหน้าชื่อผู้ใช้และชื่อแอปพลิเคชันในทุกหน้า หากเราต้องการสร้างหน้าเพื่อแสดงวัตถุลำดับงานนำเสนอเราอาจแก้ไขโมเดลงานนำเสนอดังต่อไปนี้:
public class PresentationOrder
{
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
public string CustomerName { get; set; }
public Decimal OrderAmount { get; set; }
public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}
การออกแบบนี้อาจใช้งานได้ ... แต่ถ้าเราต้องการสร้างเพจที่จะแสดงรายการคำสั่งซื้อ คุณสมบัติ PageTitle, ชื่อผู้ใช้และชื่อแอปพลิเคชันจะถูกทำซ้ำและไม่สะดวกในการใช้งาน นอกจากนี้ถ้าเราต้องการกำหนดตรรกะระดับหน้าบางส่วนในนวกรรมิกของคลาส? เราไม่สามารถทำเช่นนั้นได้อีกต่อไปหากเราสร้างอินสแตนซ์สำหรับทุกคำสั่งซื้อที่จะแสดง
องค์ประกอบมากกว่ามรดก
นี่คือวิธีที่เราอาจพิจารณาปัจจัยรูปแบบการนำเสนอเพื่อให้มันกลายเป็นรูปแบบมุมมองที่แท้จริงและจะเป็นประโยชน์สำหรับการแสดงวัตถุ PresentationOrder เดียวหรือชุดของวัตถุ PresentationOrder:
public class PresentationOrderVM
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business properties
public PresentationOrder Order { get; set; }
}
public class PresentationOrderVM
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business properties
public List<PresentationOrder> Orders { get; set; }
}
การดูสองคลาสข้างต้นเราสามารถเห็นได้ว่าวิธีหนึ่งที่จะคิดเกี่ยวกับโมเดลมุมมองคือมันเป็นโมเดลการนำเสนอที่มีโมเดลการนำเสนออื่นเป็นคุณสมบัติ โมเดลการนำเสนอระดับบนสุด (เช่นโมเดลการดู) มีคุณสมบัติที่เกี่ยวข้องกับเพจหรือแอปพลิเคชันในขณะที่โมเดลการนำเสนอ (คุณสมบัติ) มีคุณสมบัติที่เกี่ยวข้องกับข้อมูลแอปพลิเคชัน
เราสามารถดำเนินการออกแบบของเราอีกขั้นหนึ่งและสร้างคลาสโมเดลมุมมองพื้นฐานที่สามารถใช้ไม่เพียง แต่สำหรับ PresentationOrders แต่สำหรับคลาสอื่นเช่นกัน:
public class BaseViewModel
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
}
ตอนนี้เราสามารถทำให้ PresentationOrderVM ของเราง่ายขึ้นเช่นนี้:
public class PresentationOrderVM : BaseViewModel
{
// Business properties
public PresentationOrder Order { get; set; }
}
public class PresentationOrderVM : BaseViewModel
{
// Business properties
public List<PresentationOrder> Orders { get; set; }
}
เราสามารถทำให้ BaseViewModel ของเราสามารถใช้งานได้อีกครั้งโดยทำให้เป็นแบบทั่วไป:
public class BaseViewModel<T>
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business property
public T BusinessObject { get; set; }
}
ตอนนี้การใช้งานของเราง่าย
public class PresentationOrderVM : BaseViewModel<PresentationOrder>
{
// done!
}
public class PresentationOrderVM : BaseViewModel<List<PresentationOrder>>
{
// done!
}
MyViewModel<MyPresModel>
หากคุณมีคุณสมบัติที่เฉพาะเจาะจงสำหรับมุมมองและไม่เกี่ยวข้องกับที่เก็บ DB / Service / Data มันเป็นแนวปฏิบัติที่ดีในการใช้ ViewModels สมมติว่าคุณต้องการปล่อยให้ช่องทำเครื่องหมายถูกเลือกโดยยึดตามเขตข้อมูล DB (หรือสอง) แต่เขตข้อมูล DB นั้นไม่ใช่บูลีน ในขณะที่มันเป็นไปได้ที่จะสร้างคุณสมบัติเหล่านี้ในรูปแบบของตัวเองและทำให้มันถูกซ่อนไว้จากการผูกกับข้อมูลคุณอาจไม่ต้องการถ่วงรูปแบบขึ้นอยู่กับจำนวนของเขตข้อมูลและการทำธุรกรรมดังกล่าว
หากมีข้อมูลและ / หรือการแปลงเฉพาะของมุมมองที่เฉพาะเจาะจงน้อยเกินไปคุณสามารถใช้โมเดลได้
ฉันไม่ได้อ่านโพสต์ทั้งหมด แต่ทุกคำตอบดูเหมือนจะหายไปหนึ่งแนวคิดที่ช่วยให้ฉัน "รับ" ...
หาก Model เป็นแบบเดียวกับตารางฐานข้อมูลดังนั้น ViewModel จะคล้ายกับมุมมองฐานข้อมูล- โดยทั่วไปมุมมองจะส่งคืนข้อมูลจำนวนเล็กน้อยจากตารางเดียวหรือชุดข้อมูลที่ซับซ้อนจากหลายตาราง (รวม)
ฉันพบว่าตัวเองใช้ ViewModels เพื่อส่งผ่านข้อมูลไปยังมุมมอง / แบบฟอร์มจากนั้นถ่ายโอนข้อมูลนั้นไปยังรุ่นที่ถูกต้องเมื่อแบบฟอร์มโพสต์กลับไปที่ตัวควบคุม - ยังมีประโยชน์มากสำหรับการจัดเก็บรายการ (IEnumerable)
MVC ไม่มี viewmodel: มันมี model, view และ controller viewmodel เป็นส่วนหนึ่งของ MVVM (Model-View-Viewmodel) MVVM ได้มาจากรูปแบบการนำเสนอและได้รับความนิยมใน WPF ควรมีแบบจำลองใน MVVM แต่คนส่วนใหญ่พลาดจุดของรูปแบบนั้นอย่างสมบูรณ์และพวกเขาจะมีเพียงมุมมองและโมเดล โมเดลใน MVC คล้ายกับโมเดลใน MVVM
ใน MVC กระบวนการแบ่งออกเป็น 3 ความรับผิดชอบที่แตกต่างกัน:
MVC ไม่เหมาะสำหรับเว็บแอปพลิเคชัน มันเป็นรูปแบบที่ได้รับการแนะนำโดย Smalltalk สำหรับการสร้างแอปพลิเคชันเดสก์ท็อป สภาพแวดล้อมเว็บทำงานแตกต่างอย่างสิ้นเชิง มันไม่สมเหตุสมผลเลยที่จะคัดลอกแนวคิดอายุ 40 ปีจากการพัฒนาเดสก์ท็อปและวางลงในสภาพแวดล้อมของเว็บ อย่างไรก็ตามผู้คนจำนวนมากคิดว่ามันโอเคเพราะแอปพลิเคชันของพวกเขารวบรวมและส่งคืนค่าที่ถูกต้อง นั่นคือในความคิดของฉันไม่เพียงพอที่จะประกาศตัวเลือกการออกแบบบางอย่างเช่นตกลง
ตัวอย่างของแบบจำลองในเว็บแอปพลิเคชันอาจเป็น:
public class LoginModel
{
private readonly AuthenticationService authentication;
public LoginModel(AuthenticationService authentication)
{
this.authentication = authentication;
}
public bool Login()
{
return authentication.Login(Username, Password);
}
public string Username { get; set; }
public string Password { get; set; }
}
คอนโทรลเลอร์สามารถใช้งานดังนี้:
public class LoginController
{
[HttpPost]
public ActionResult Login(LoginModel model)
{
bool success = model.Login();
if (success)
{
return new RedirectResult("/dashboard");
}
else
{
TempData["message"] = "Invalid username and/or password";
return new RedirectResult("/login");
}
}
}
วิธีการควบคุมและรุ่นของคุณจะเล็กทดสอบได้อย่างง่ายดายและตรงประเด็น
ดูโมเดล a เป็นคลาสแบบง่ายซึ่งสามารถมีคุณสมบัติคลาสได้มากกว่าหนึ่งคลาส เราใช้มันเพื่อสืบทอดคุณสมบัติที่ต้องการทั้งหมดเช่นฉันมีนักเรียนสองวิชาและวิชา
Public class Student
{
public int Id {get; set;}
public string Name {get; set;}
}
Public class Subject
{
public int SubjectID {get; set;}
public string SubjectName {get; set;}
}
ตอนนี้เราต้องการแสดงบันทึกชื่อนักเรียนและชื่อวิชาในมุมมอง (ใน MVC) แต่ไม่สามารถเพิ่มมากกว่าหนึ่งคลาสเช่น:
@model ProjectName.Model.Student
@model ProjectName.Model.Subject
รหัสด้านบนจะทำให้เกิดข้อผิดพลาด ...
ตอนนี้เราสร้างคลาสหนึ่งและสามารถตั้งชื่อใด ๆ ได้ แต่รูปแบบ "XyzViewModel" จะทำให้เข้าใจง่ายขึ้น มันเป็นแนวคิดที่สืบทอด ตอนนี้เราสร้างคลาสที่สามด้วยชื่อต่อไปนี้:
public class StudentViewModel:Subject
{
public int ID {get; set;}
public string Name {get; set;}
}
ตอนนี้เราใช้ ViewModel นี้ในมุมมอง
@model ProjectName.Model.StudentViewModel
ตอนนี้เราสามารถเข้าถึงคุณสมบัติทั้งหมดของ StudentViewModel และคลาสที่สืบทอดในมุมมอง
มีตัวอย่างมากมายให้ฉันอธิบายอย่างชัดเจนและกรอบ
ViewModel = รุ่นที่สร้างขึ้นเพื่อให้บริการมุมมอง
มุมมอง ASP.NET MVC ไม่สามารถมีโมเดลได้มากกว่าหนึ่งโมเดลดังนั้นหากเราต้องการแสดงคุณสมบัติจากโมเดลมากกว่าหนึ่งโมเดลในมุมมองมันเป็นไปไม่ได้ ViewModel ทำหน้าที่จุดประสงค์นี้
ดูโมเดลเป็นคลาสโมเดลที่สามารถเก็บเฉพาะคุณสมบัติเหล่านั้นที่จำเป็นสำหรับมุมมอง นอกจากนี้ยังสามารถมีคุณสมบัติจากมากกว่าหนึ่งเอนทิตี (ตาราง) ของฐานข้อมูล ตามชื่อที่แนะนำโมเดลนี้ถูกสร้างขึ้นเฉพาะกับข้อกำหนดมุมมอง
ดูตัวอย่างน้อยรุ่นอยู่ด้านล่าง
ViewModel ยังสามารถใช้ในการแทรกอัปเดตบันทึกลงในเอนทิตีมากกว่าหนึ่งรายการได้อย่างไรก็ตามการใช้งานหลักของ ViewModel คือการแสดงคอลัมน์จากเอนทิตีหลาย (โมเดล) ลงในมุมมองเดียว
วิธีการสร้าง ViewModel เหมือนกับการสร้าง Model วิธีการสร้างมุมมองสำหรับ Viewmodel นั้นเหมือนกับการสร้างมุมมองสำหรับ Model
นี่เป็นตัวอย่างเล็ก ๆ ของข้อมูลโดยใช้รายการ ViewModel
หวังว่านี่จะเป็นประโยชน์
ViewModel เป็นวิธีการแก้ปัญหาที่แก้ไขความซุ่มซ่ามแนวคิดของกรอบ MVC เพราะมันหมายถึงชั้นที่ 4 ในสถาปัตยกรรม Model-View-Controller แบบ 3 ชั้น เมื่อ Model (โมเดลโดเมน) ไม่เหมาะสมใหญ่เกินไป (ใหญ่กว่า 2-3 ฟิลด์) สำหรับมุมมองเราสร้าง ViewModel ที่มีขนาดเล็กกว่าเพื่อส่งต่อไปยัง View
มุมมองโมเดลเป็นโมเดลแนวคิดของข้อมูล มันใช้เพื่อรับทั้งชุดย่อยหรือรวมข้อมูลจากตารางที่แตกต่างกัน
คุณอาจต้องการคุณสมบัติที่เฉพาะเจาะจงเท่านั้นดังนั้นสิ่งนี้จะช่วยให้คุณสามารถโหลดคุณสมบัติเหล่านั้นได้และไม่ใช่คุณสมบัติที่ไม่จำเป็นเพิ่มเติม
การออกแบบ ViewModel
public class UserLoginViewModel
{
[Required(ErrorMessage = "Please enter your username")]
[Display(Name = "User Name")]
[MaxLength(50)]
public string UserName { get; set; }
[Required(ErrorMessage = "Please enter your password")]
[Display(Name = "Password")]
[MaxLength(50)]
public string Password { get; set; }
}
การนำเสนอโมเดลมุมมองในมุมมอง
@model MyModels.UserLoginViewModel
@{
ViewBag.Title = "User Login";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm())
{
<div class="editor-label">
@Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
@Html.TextBoxFor(m => m.UserName)
@Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
@Html.PasswordFor(m => m.Password)
@Html.ValidationMessageFor(m => m.Password)
</div>
<p>
<input type="submit" value="Log In" />
</p>
</div>
}
ทำงานกับ Action
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(UserLoginViewModel user)
{
// To acces data using LINQ
DataClassesDataContext mobjentity = new DataClassesDataContext();
if (ModelState.IsValid)
{
try
{
var q = mobjentity.tblUsers.Where(m => m.UserName == user.UserName && m.Password == user.Password).ToList();
if (q.Count > 0)
{
return RedirectToAction("MyAccount");
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
catch (Exception ex)
{
}
}
return View(user);
}
View Model เป็นคลาสที่เราสามารถใช้สำหรับการแสดงผลข้อมูลบน View สมมติว่าคุณมีสถานที่สองรายการและประเภทสถานที่และคุณต้องการเข้าถึงข้อมูลจากทั้งสองหน่วยงานโดยใช้รูปแบบเดียวจากนั้นเราจะใช้ ViewModel
public class Place
{
public int PlaceId { get; set; }
public string PlaceName { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
public string BestTime { get; set; }
}
public class Category
{
public int ID { get; set; }
public int? PlaceId { get; set; }
public string PlaceCategoryName { get; set; }
public string PlaceCategoryType { get; set; }
}
public class PlaceCategoryviewModel
{
public string PlaceName { get; set; }
public string BestTime { get; set; }
public string PlaceCategoryName { get; set; }
public string PlaceCategoryType { get; set; }
}
ดังนั้นในตัวอย่างข้างต้น Place และ Category คือเอนทิตีที่แตกต่างกันสองรายการและ PlaceCategory viewmodel คือ ViewModel ซึ่งเราสามารถใช้บน View
หากคุณต้องการที่จะศึกษารหัสวิธีการตั้งค่าเป็น "พื้นฐาน" แอพลิเคชันเว็บที่มี ViewModels ฉันสามารถให้คำแนะนำในการดาวน์โหลดโค้ดนี้บน GitHub: https://github.com/ajsaulsberry/BlipAjax ฉันพัฒนาแอปพลิเคชันองค์กรขนาดใหญ่ เมื่อคุณทำเช่นนี้มันมีปัญหาในการตั้งค่าสถาปัตยกรรมที่ดีที่จัดการฟังก์ชัน "ViewModel" ทั้งหมดนี้ ฉันคิดว่า BlipAjax คุณจะมี "baseline" ที่ดีมากในการเริ่มต้น มันเป็นเพียงเว็บไซต์ที่เรียบง่าย แต่ยอดเยี่ยมในความเรียบง่าย ฉันชอบวิธีที่พวกเขาใช้ภาษาอังกฤษเพื่อชี้สิ่งที่จำเป็นจริงๆในแอปพลิเคชัน