สองรุ่นในมุมมองเดียวใน ASP MVC 3


92

ฉันมี 2 รุ่น:

public class Person
{
    public int PersonID { get; set; }
    public string PersonName { get; set; }
}
public class Order
{
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

ฉันต้องการแก้ไขออบเจ็กต์ของทั้งสองคลาสในมุมมองเดียวดังนั้นฉันต้องการบางสิ่งเช่น:

@model _try2models.Models.Person
@model _try2models.Models.Order

@using(Html.BeginForm())
{
    @Html.EditorFor(x => x.PersonID)
    @Html.EditorFor(x => x.PersonName)
    @Html.EditorFor(x=>x.OrderID)
    @Html.EditorFor(x => x.TotalSum)
}

แน่นอนว่าสิ่งนี้ไม่ได้ผล: อนุญาตให้ใช้คำสั่ง "model" เพียงคำสั่งเดียวในไฟล์. cshtml อาจมีวิธีแก้ปัญหาบางอย่าง?


1
คำตอบของฉันช่วยคุณได้ไหม
Andrew

ฉันใช้ViewBagกับแต่ละมุมมองได้ผลสำหรับฉันตรวจสอบสิ่งนี้เพื่อทราบตัวเลือกหลายตัวช่วยประหยัดเวลาเพียงเล็กน้อยสำหรับฉันแทนที่จะสร้างโมเดลมุมมองหรือมุมมองบางส่วน
shaijut

คำตอบ:


119

สร้างโมเดลมุมมองหลักที่มีทั้งสองโมเดล

public class MainPageModel{
    public Model1 Model1{get; set;}
    public Model2 Model2{get; set;}
}

ด้วยวิธีนี้คุณสามารถเพิ่มโมเดลเพิ่มเติมในภายหลังโดยใช้ความพยายามขั้นต่ำ


2
เมื่อใช้โซลูชันนี้โปรดทราบว่าการเปลี่ยนแปลง Model1 หรือ Model2 อาจส่งผลกระทบต่อ MainPageModel ของคุณ นอกจากนี้ยังมีข้อมูลหลักมากกว่ามุมมองที่ต้องการจริงๆ หาก MainPage ของคุณเป็นการรวมกันของสิ่งต่างๆที่มีอยู่แล้วในตัวควบคุมอื่น ๆ การเปลี่ยนจาก RenderPartial เป็น RenderAction จะช่วยให้คุณแยกสิ่งต่างๆออกจากกันได้อย่างเรียบร้อย ลองอ่าน Law of Demeter: en.wikipedia.org/wiki/Law_of_Demeter
Fenton

1
@Andi - ฉันสร้าง Model ตามที่คุณแนะนำไว้ข้างต้น แต่เมื่อฉันคลิกขวาที่คอนโทรลเลอร์และพยายามสร้าง Crud controller มันไม่ทำงาน? ข้อเสนอแนะใด ๆ ? ฉันจะสร้างตัวควบคุม crud ด้วยมุมมองอัตโนมัติสำหรับรุ่นด้านบนได้อย่างไร
NoviceMe

2
จากวิธีการทั้งหมดที่ฉันเห็นในการแก้ปัญหานี้นี่เป็นวิธีที่ได้ผลดีที่สุดสำหรับฉัน เป็นวิธีที่ง่ายที่สุดที่ได้ผล
Ciaran Gallagher

4
เมื่อคุณถามตัวเองว่า "ทำไมฉันถึงไม่คิดถึงสิ่งนั้นมาก่อน" ทางออกที่ยอดเยี่ยม
Rafael AMS

1
@ Andi ฉันจะเปิดเผยวิธีการของโมเดลที่เกี่ยวข้องในคอนโทรลเลอร์ได้อย่างไร?
Volatil3

53

ในการใช้ทูเปิลคุณต้องทำสิ่งต่อไปนี้ในมุมมองเปลี่ยนโมเดลเป็น:

@model Tuple<Person,Order>

ในการใช้วิธีการ @html คุณต้องดำเนินการดังต่อไปนี้:

@Html.DisplayNameFor(tuple => tuple.Item1.PersonId)

หรือ

@Html.ActionLink("Edit", "Edit", new { id=Model.Item1.Id }) |

Item1 ระบุพารามิเตอร์แรกที่ส่งผ่านไปยังเมธอด Tuple และคุณสามารถใช้ Item2 เพื่อเข้าถึงโมเดลที่สองและอื่น ๆ

ในคอนโทรลเลอร์ของคุณคุณต้องสร้างตัวแปรประเภท Tuple จากนั้นส่งต่อไปยังมุมมอง:

    public ActionResult Details(int id = 0)
    {
        Person person = db.Persons.Find(id);
        if (person == null)
        {
            return HttpNotFound();
        }
        var tuple = new Tuple<Person, Order>(person,new Order());

        return View(tuple);
    }

อีกตัวอย่างหนึ่ง: หลายรุ่นในมุมมอง


1
อย่าใช้ a Tupleในกรณีนี้ - OP ต้องการแก้ไขข้อมูลและTupleไม่มีตัวสร้างเริ่มต้นดังนั้นโมเดลจึงไม่สามารถผูกมัดได้เมื่อส่งแบบฟอร์ม

อย่าพูดไม่เคย ที่นี่แข็งแกร่งเล็กน้อย
johnny

47

ตัวเลือกซึ่งไม่ได้มีความต้องการที่จะสร้างที่กำหนดเองอีกรุ่นคือการใช้Tuple <>

@model Tuple<Person,Order>

มันไม่สะอาดเท่ากับการสร้างคลาสใหม่ที่มีทั้งสองอย่างตามคำตอบของ Andi แต่มันก็ทำงานได้


ใน mvc 3 จะให้ข้อผิดพลาดมีเพียงคำสั่ง 'model' เดียวเท่านั้นที่ได้รับอนุญาตในไฟล์ มีความคิดอย่างไรที่จะแก้ปัญหานี้?
GibboK

1
@ GibboK - ฉันใช้มันใน MVC3 ได้ดี ตรวจสอบให้แน่ใจว่าคุณไม่มีสอง@modelบรรทัดแยกกัน?
Bobson

3
คุณสามารถรับคุณสมบัติของแต่ละรุ่นด้วย: @Model.Item1.Propertyและ@Model.Item2.PropertyสำหรับPersonและOrderตามลำดับ
user2019515

1
ฉันใช้ Tuple ในมุมมองของฉัน แต่ฉันไม่สามารถรับค่าโมเดลในคอนโทรลเลอร์ของฉันได้ แต่ในขณะที่ฉันใช้โมเดลมุมมองผู้ปกครองตามที่ @Andi แนะนำฉันได้รับค่าโมเดลในคอนโทรลเลอร์ของฉัน
เรนท

1
@StephenMuecke - อืม. ฉันไม่เคยคิดอย่างนั้น แต่คุณพูดถูก เหตุผลอีกประการหนึ่งที่คำตอบของ Andrew คือวัตถุประสงค์ทั่วไปที่ดีกว่า เมื่อคุณใช้ทางเลือกที่มีน้ำหนักเบา (เช่นนี้) คุณจะเลิกใช้ฟังก์ชันการทำงาน
Bobson

10

หากคุณเป็นแฟนตัวยงที่มีโมเดลแบนมากเพียงเพื่อรองรับมุมมองคุณควรสร้างโมเดลเฉพาะสำหรับมุมมองนี้โดยเฉพาะ ...

public class EditViewModel
    public int PersonID { get; set; }
    public string PersonName { get; set; }
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

หลายคนใช้ AutoMapper เพื่อแมปจากวัตถุในโดเมนไปยังมุมมองแบบแบน

แนวคิดของโมเดลมุมมองคือมันรองรับมุมมองเท่านั้น - ไม่มีอะไรอื่น คุณมีหนึ่งรายการต่อการดูเพื่อให้แน่ใจว่ามีเฉพาะสิ่งที่จำเป็นสำหรับมุมมองนั้นไม่ใช่คุณสมบัติมากมายที่คุณต้องการสำหรับมุมมองอื่น ๆ


5

โอเคทุกคนมีเหตุผลและฉันก็เอาชิ้นส่วนทั้งหมดมาวางไว้ที่นี่เพื่อช่วยมือใหม่อย่างฉันที่ต้องการคำอธิบายตั้งแต่ต้นจนจบ

คุณสร้างคลาสใหญ่ที่มี 2 คลาสตามคำตอบของ @ Andrew

public class teamBoards{
    public Boards Boards{get; set;}
    public Team Team{get; set;}
}

จากนั้นในคอนโทรลเลอร์ของคุณคุณกรอก 2 รุ่น บางครั้งคุณต้องกรอกเพียงอย่างเดียว จากนั้นในทางกลับกันคุณอ้างอิงโมเดลขนาดใหญ่และจะนำ 2 ภายในไปที่ View

            TeamBoards teamBoards = new TeamBoards();


        teamBoards.Boards = (from b in db.Boards
                               where b.TeamId == id
                               select b).ToList();
        teamBoards.Team = (from t in db.Teams
                              where t.TeamId == id
                          select t).FirstOrDefault();

 return View(teamBoards);

ที่ด้านบนสุดของมุมมอง

@model yourNamespace.Models.teamBoards

จากนั้นโหลดอินพุตของคุณหรือแสดงการอ้างอิงเนื้อหาโมเดลขนาดใหญ่:

 @Html.EditorFor(m => Model.Board.yourField)
 @Html.ValidationMessageFor(m => Model.Board.yourField, "", new { @class = "text-danger-yellow" })

 @Html.EditorFor(m => Model.Team.yourField)
 @Html.ValidationMessageFor(m => Model.Team.yourField, "", new { @class = "text-danger-yellow" })

และ. . . กลับไปที่ฟาร์มปศุสัตว์เมื่อโพสต์เข้ามาให้อ้างอิง Big Class:

 public ActionResult ContactNewspaper(teamBoards teamboards)

และใช้ประโยชน์จากสิ่งที่โมเดลส่งคืน:

string yourVariable = teamboards.Team.yourField;

อาจมีข้อมูลการตรวจสอบความถูกต้อง DataAnnotation ในคลาสและอาจใส่ if (ModelState.IsValid) ไว้ที่ด้านบนสุดของบล็อกบันทึก / แก้ไข . .


4

ในความเป็นจริงมีวิธีใช้แบบจำลองสองแบบหรือมากกว่าในมุมมองเดียวโดยไม่ต้องรวมไว้ในคลาสที่มีทั้งสองอย่าง

การใช้พนักงานเป็นตัวอย่าง:

@model Employee

ได้รับการปฏิบัติจริงเช่น

@{ var Model = ViewBag.model as Employee; }

ดังนั้นวิธีการ View (พนักงาน) คือการตั้งค่าโมเดลของคุณเป็น ViewBag จากนั้น ViewEngine จะแคสต์มัน

ซึ่งหมายความว่า

ViewBag.departments = GetListOfDepartments();
    return View(employee);

สามารถใช้งานได้เช่น

            @model  Employee
        @{
                var DepartmentModel = ViewBag.departments as List<Department>;
        }

โดยพื้นฐานแล้วคุณสามารถใช้อะไรก็ได้ใน ViewBag ของคุณเป็น "โมเดล" เพราะนั่นคือวิธีการทำงาน ฉันไม่ได้บอกว่านี่เป็นอุดมคติทางสถาปัตยกรรม แต่เป็นไปได้


3

เพียงแค่สร้างโมเดลมุมมองเดียวที่มีข้อมูลที่จำเป็นทั้งหมดในนั้นปกติสิ่งที่ฉันทำคือสร้างแบบจำลองสำหรับทุกมุมมองเพื่อให้ฉันสามารถเจาะจงได้ในทุกมุมมองไม่ว่าจะเป็นแบบนั้นหรือสร้างแบบจำลองหลักและรับช่วงต่อ หรือสร้างแบบจำลองที่มีทั้งมุมมอง

โดยส่วนตัวแล้วฉันจะเพิ่มลงในโมเดลเดียว แต่นั่นคือวิธีที่ฉันทำ:

public class xViewModel
{
    public int PersonID { get; set; }
    public string PersonName { get; set; }
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

@model project.Models.Home.xViewModel

@using(Html.BeginForm())
{
    @Html.EditorFor(x => x.PersonID)
    @Html.EditorFor(x => x.PersonName)
    @Html.EditorFor(x => x.OrderID)
    @Html.EditorFor(x => x.TotalSum)
}

1

คุณสามารถใช้รูปแบบการนำเสนอhttp://martinfowler.com/eaaDev/PresentationModel.html

โมเดล "มุมมอง" ของงานนำเสนอนี้สามารถมีทั้งบุคคลและลำดับ
ชั้นเรียนใหม่นี้สามารถเป็นต้นแบบที่คุณดูอ้างอิงได้


1
รูปแบบการนำเสนอควรมีข้อมูลที่จำเป็นซึ่งอาจมาจากบุคคลและคำสั่ง ไม่ควรมีวัตถุโดเมนบุคคลหรือคำสั่งซื้อจริงๆ มุมมองแยกการแสดงผลออกจากโดเมนพื้นฐาน
Fenton

0

อีกวิธีหนึ่งที่ไม่เคยพูดถึงคือสร้างมุมมองใน MSSQL ด้วยข้อมูลทั้งหมดที่คุณต้องการนำเสนอ จากนั้นใช้ LINQ กับ SQL หรืออะไรก็ได้เพื่อแมป ในตัวควบคุมของคุณกลับไปที่มุมมอง เสร็จแล้ว


0

คุณไม่สามารถประกาศสองรุ่นในมุมมองหนึ่งพยายามที่จะใช้งานHtml.Action("Person", "[YourController]")Html.Action("Order", "[YourController]")

โชคดี.


สิ่งนี้ทำอะไร?
johnny

0

นอกจากโมเดลมุมมองเดียวใน asp.net คุณยังสามารถสร้างมุมมองบางส่วนได้หลายมุมมองและกำหนดมุมมองโมเดลที่แตกต่างกันให้กับทุกมุมมองตัวอย่างเช่น

   @{
        Layout = null;
    }

    @model Person;

    <input type="text" asp-for="PersonID" />
    <input type="text" asp-for="PersonName" />

จากนั้นอีกมุมมองบางส่วน Model สำหรับรูปแบบการสั่งซื้อ

    @{
        Layout = null;
     }

    @model Order;

    <input type="text" asp-for="OrderID" />
    <input type="text" asp-for="TotalSum" />

จากนั้นในมุมมองหลักของคุณให้โหลดทั้งมุมมองบางส่วนโดย

<partial name="PersonPartialView" />
<partial name="OrderPartialView" />

-1

ฉันหวังว่าคุณจะพบว่ามันเป็นประโยชน์ !!

ฉันใช้ ViewBag For Project และ Model สำหรับงานด้วยวิธีนี้ฉันใช้สองโมเดลในมุมมองเดียวและในคอนโทรลเลอร์ฉันกำหนดค่าหรือข้อมูลของวิวแบ็ก

List<tblproject> Plist = new List<tblproject>();
            Plist = ps.getmanagerproject(c, id);

            ViewBag.projectList = Plist.Select(x => new SelectListItem
            {
                Value = x.ProjectId.ToString(),
                Text = x.Title
            });

และในมุมมอง tbltask และ projectlist เป็นโมเดลที่แตกต่างกันสองแบบของฉัน

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} @ รายการรุ่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.