ฉันอยากจะบอกว่าคุณใช้คำว่า ViewModel ซ้ำสำหรับทั้งสองทิศทางของการโต้ตอบกับไคลเอนต์ หากคุณอ่านโค้ด ASP.NET MVC ในไวด์มากพอคุณอาจเห็นความแตกต่างระหว่าง ViewModel และ EditModel ผมคิดว่าเป็นสิ่งสำคัญ
ViewModel แสดงถึงข้อมูลทั้งหมดที่จำเป็นในการแสดงผลมุมมอง ซึ่งอาจรวมถึงข้อมูลที่แสดงผลในตำแหน่งที่ไม่มีการโต้ตอบแบบคงที่และข้อมูลเพื่อทำการตรวจสอบเพื่อตัดสินใจว่าจะแสดงผลแบบใดกันแน่ โดยทั่วไปแอ็คชัน Controller GET มีหน้าที่ในการบรรจุ ViewModel สำหรับ View
EditModel (หรืออาจจะเป็น ActionModel) แทนข้อมูลที่จำเป็นในการดำเนินการที่ผู้ใช้ต้องการทำสำหรับ POST นั้น ดังนั้น EditModel จึงพยายามอธิบายการกระทำจริงๆ สิ่งนี้อาจจะยกเว้นข้อมูลบางส่วนจาก ViewModel และแม้ว่าจะเกี่ยวข้องกันฉันคิดว่าสิ่งสำคัญคือต้องตระหนักว่ามันแตกต่างกันอย่างแน่นอน
หนึ่งความคิด
ที่กล่าวว่าคุณสามารถมีการกำหนดค่า AutoMapper ได้อย่างง่ายดายสำหรับการเริ่มต้นจาก Model -> ViewModel และอีกแบบหนึ่งเพื่อไปจาก EditModel -> Model จากนั้นการกระทำของคอนโทรลเลอร์ที่แตกต่างกันก็ต้องใช้ AutoMapper นรก EditModel อาจมีฟังก์ชั่นในการตรวจสอบคุณสมบัติของมันกับโมเดลและเพื่อใช้ค่าเหล่านั้นกับโมเดลเอง มันไม่ได้ทำอย่างอื่นและคุณมี ModelBinders ใน MVC เพื่อแมปคำขอกับ EditModel อยู่ดี
แนวคิดอื่น
นอกเหนือจากนั้นสิ่งที่ฉันคิดเกี่ยวกับเมื่อเร็ว ๆ นี้ประเภทนี้ได้ผลจากแนวคิดของ ActionModel ก็คือสิ่งที่ลูกค้าโพสต์กลับมาหาคุณนั้นเป็นคำอธิบายของการกระทำหลายอย่างที่ผู้ใช้ทำไม่ใช่แค่ข้อมูลขนาดใหญ่เพียงก้อนเดียว แน่นอนว่าสิ่งนี้จะต้องใช้ Javascript ในฝั่งไคลเอ็นต์ในการจัดการ แต่ฉันคิดว่าแนวคิดนี้น่าสนใจ
โดยพื้นฐานแล้วเมื่อผู้ใช้ดำเนินการบนหน้าจอที่คุณนำเสนอ Javascript จะเริ่มสร้างรายการวัตถุการดำเนินการ ตัวอย่างอาจเป็นไปได้ว่าผู้ใช้อยู่ที่หน้าจอข้อมูลพนักงาน พวกเขาอัปเดตนามสกุลและเพิ่มที่อยู่ใหม่เนื่องจากพนักงานเพิ่งแต่งงาน ภายใต้ฝาครอบนี้จะสร้างChangeEmployeeName
และAddEmployeeMailingAddress
วัตถุในรายการ ผู้ใช้คลิก 'บันทึก' เพื่อดำเนินการเปลี่ยนแปลงและคุณส่งรายการของวัตถุสองชิ้นซึ่งแต่ละรายการมีเพียงข้อมูลที่จำเป็นในการดำเนินการแต่ละอย่าง
คุณจะต้องมี ModelBinder ที่ชาญฉลาดมากขึ้นจากนั้นจึงเป็นค่าเริ่มต้น แต่ serializer JSON ที่ดีควรสามารถดูแลการแมปของวัตถุการดำเนินการฝั่งไคลเอ็นต์กับวัตถุฝั่งเซิร์ฟเวอร์ได้ ฝั่งเซิร์ฟเวอร์ (หากคุณอยู่ในสภาพแวดล้อมแบบ 2 ชั้น) อาจมีเมธอดที่ดำเนินการกับโมเดลที่ทำงานด้วยได้อย่างง่ายดาย ดังนั้นการดำเนินการของคอนโทรลเลอร์จะจบลงด้วยการได้รับ Id สำหรับอินสแตนซ์ Model เพื่อดึงและรายการของการดำเนินการที่จะดำเนินการ หรือการดำเนินการมีรหัสอยู่เพื่อให้แยกออกจากกัน
ดังนั้นอาจมีบางอย่างเช่นนี้เกิดขึ้นที่ฝั่งเซิร์ฟเวอร์:
public interface IUserAction<TModel>
{
long ModelId { get; set; }
IEnumerable<string> Validate(TModel model);
void Complete(TModel model);
}
[Transaction]
public ActionResult Save(IEnumerable<IUserAction<Employee>> actions)
{
var errors = new List<string>();
foreach( var action in actions )
{
var employee = _employeeRepository.Get(action.ModelId);
errors.AddRange(action.Validate(employee));
}
foreach( var action in editModel.UserActions )
{
var employee = _employeeRepository.Get(action.ModelId);
action.Complete(employee);
_employeeRepository.Update(employee);
}
}
นั่นทำให้การดำเนินการโพสต์กลับค่อนข้างเป็นเรื่องธรรมดาเนื่องจากคุณใช้ ModelBinder ของคุณเพื่อให้คุณได้รับอินสแตนซ์ IUserAction ที่ถูกต้องและอินสแตนซ์ IUserAction ของคุณเพื่อดำเนินการตรรกะที่ถูกต้องเองหรือ (เป็นไปได้มากกว่า) เรียกเข้าสู่ Model พร้อมข้อมูล
หากคุณอยู่ในสภาพแวดล้อม 3 ชั้น IUserAction สามารถสร้าง DTO แบบง่าย ๆ เพื่อยิงข้ามขอบเขตและดำเนินการในวิธีการที่คล้ายกันในเลเยอร์แอป ขึ้นอยู่กับว่าคุณทำเลเยอร์นั้นอย่างไรมันสามารถแบ่งออกได้ง่ายมากและยังคงอยู่ในธุรกรรม (สิ่งที่อยู่ในใจคือคำขอ / คำตอบของ Agatha และการใช้ประโยชน์จากแผนที่ข้อมูลประจำตัวของ DI และ NHibernate)
อย่างไรก็ตามฉันแน่ใจว่ามันไม่ใช่ความคิดที่สมบูรณ์แบบมันต้องใช้ JS ในฝั่งไคลเอนต์ในการจัดการและฉันยังไม่สามารถทำโปรเจ็กต์เพื่อดูว่ามันออกมาอย่างไร แต่โพสต์พยายามคิดว่าจะทำอย่างไร ไปที่นั่นแล้วกลับมาอีกครั้งดังนั้นฉันคิดว่าฉันจะให้ความคิดของฉัน ฉันหวังว่ามันจะช่วยได้และฉันชอบที่จะได้ยินวิธีอื่น ๆ ในการจัดการการโต้ตอบ