Dua model dalam satu tampilan di ASP MVC 3

92

Saya memiliki 2 model:

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; }
}

Saya ingin mengedit objek dari kelas KEDUA dalam tampilan TUNGGAL, jadi saya membutuhkan sesuatu seperti:

@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)
}

Ini, tentu saja, tidak berfungsi: Hanya satu pernyataan 'model' yang diperbolehkan dalam file .cshtml. Mungkin ada beberapa solusi?

Smarty
sumber
1
Apakah jawaban saya membantu Anda?
Andrew
saya digunakan ViewBagdengan untuk setiap tampilan bekerja untuk saya, periksa ini untuk mengetahui beberapa opsi, menghemat sedikit waktu untuk saya daripada membuat model tampilan atau tampilan parsial
shaijut

Jawaban:

119

Buat model tampilan induk yang berisi kedua model.

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

Dengan cara ini Anda dapat menambahkan model tambahan di kemudian hari dengan usaha yang sangat minimal.

Andrew
sumber
2
Saat menggunakan solusi ini, harap diingat bahwa perubahan pada Model1 atau Model2 mungkin berdampak pada MainPageModel Anda. Juga mereka utama berisi lebih banyak data daripada yang sebenarnya dibutuhkan tampilan. Jika MainPage Anda adalah kombinasi dari hal-hal yang sudah ada di pengontrol lain, beralih dari RenderP Partial ke RenderAction akan memungkinkan Anda untuk memisahkan semuanya dengan rapi. Pertimbangkan untuk membaca Hukum Demeter: en.wikipedia.org/wiki/Law_of_Demeter
Fenton
1
@Andi - Saya membuat Model seperti yang Anda sarankan di atas. Tetapi ketika saya mengklik kanan pada pengontrol dan mencoba membuat pengontrol Crud, apakah tidak berfungsi? Ada saran? Bagaimana saya dapat membuat pengontrol kasar dengan tampilan otomatis untuk Model di atas?
NoviceMe
2
Dari semua pendekatan yang pernah saya lihat untuk memecahkan masalah ini, inilah yang paling berhasil untuk saya. Sejauh ini, ini adalah solusi paling sederhana yang berhasil.
Ciaran Gallagher
4
Saat Anda bertanya pada diri sendiri, "Mengapa Saya Tidak Memikirkan Hal Itu Sebelumnya?" Solusi hebat
Rafael AMS
1
@Andi Bagaimana cara saya mengekspos metode model masing-masing dalam pengontrol?
Volatil3
53

Untuk menggunakan tupel, Anda perlu melakukan hal berikut, dalam tampilan ubah model menjadi:

@model Tuple<Person,Order>

untuk menggunakan metode @html, Anda perlu melakukan hal berikut, yaitu:

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

atau

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

Item1 menunjukkan parameter pertama yang diteruskan ke metode Tuple dan Anda dapat menggunakan Item2 untuk mengakses model kedua dan seterusnya.

di pengontrol Anda, Anda perlu membuat variabel tipe Tuple dan kemudian meneruskannya ke tampilan:

    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);
    }

Contoh lain: Beberapa model dalam satu tampilan

Hamid Tavakoli
sumber
1
Jangan pernah menggunakan a Tupledalam kasus ini - OP ingin mengedit data, dan a Tupletidak memiliki konstruktor default sehingga model tidak dapat terikat saat formulir dikirimkan
Jangan pernah bilang tidak akan pernah. Itu sedikit kuat di sini.
johnny
47

Opsi lain yang tidak perlu membuat Model kustom adalah menggunakan Tuple <> .

@model Tuple<Person,Order>

Ini tidak sebersih membuat kelas baru yang berisi keduanya, sesuai jawaban Andi, tapi itu layak.

Bobson
sumber
di mvc 3 memberikan kesalahan Hanya satu pernyataan 'model' yang diperbolehkan dalam sebuah file. Ada ide bagaimana mengatasinya?
GibboK
1
@ GibboK - Saya menggunakannya di MVC3 dengan baik. Pastikan Anda tidak memiliki dua @modelbaris terpisah ?
Bobson
3
Anda bisa mendapatkan properti dari setiap Model dengan: @Model.Item1.Propertydan @Model.Item2.Propertyuntuk Persondan Ordermasing
user2019515
1
Saya telah menggunakan Tuple dalam View saya. Tapi, saya tidak bisa mendapatkan nilai model di controller saya. Tapi, ketika saya menggunakan model tampilan Parent seperti yang direkomendasikan @Andi, saya mendapatkan nilai model di controller saya.
Naren
1
@StephenMuecke - Hmm. Aku tidak pernah memikirkan itu, tapi kamu benar. Alasan lain mengapa jawaban Andrew adalah untuk tujuan umum yang lebih baik. Ketika Anda pergi dengan alternatif ringan (seperti ini), Anda jangan menyerah fungsi.
Bobson
10

Jika Anda adalah penggemar model yang sangat datar, hanya untuk mendukung tampilan, Anda harus membuat model khusus untuk tampilan khusus ini ...

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

Banyak orang menggunakan AutoMapper untuk memetakan dari objek domain mereka ke tampilan datar mereka.

Ide model tampilan adalah model ini hanya mendukung tampilan - tidak ada yang lain. Anda memiliki satu per tampilan untuk memastikan bahwa itu hanya berisi apa yang diperlukan untuk tampilan itu - bukan memuat properti yang Anda inginkan untuk tampilan lain.

Fenton
sumber
5

ok, semua orang masuk akal dan saya mengambil semua bagian dan meletakkannya di sini untuk membantu pemula seperti saya yang membutuhkan penjelasan awal hingga akhir.

Anda membuat kelas besar Anda yang memiliki 2 kelas, sesuai jawaban @ Andrew.

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

Kemudian di pengontrol Anda, Anda mengisi 2 model. Terkadang Anda hanya perlu mengisinya. Kemudian sebagai gantinya, Anda mereferensikan model besar dan itu akan membawa 2 di dalamnya bersamanya ke 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);

Di bagian atas Tampilan

@model yourNamespace.Models.teamBoards

Kemudian muat input atau tampilan Anda yang mereferensikan konten Model besar:

 @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" })

Dan. . . . kembali ke peternakan, ketika Post masuk, rujuk Kelas Besar:

 public ActionResult ContactNewspaper(teamBoards teamboards)

dan manfaatkan model yang dikembalikan:

string yourVariable = teamboards.Team.yourField;

Mungkin memiliki beberapa hal Validasi DataAnnotation di kelas dan mungkin meletakkan if (ModelState.IsValid) di bagian atas blok simpan / edit. . .

JustJohn
sumber
4

Sebenarnya, ada cara untuk menggunakan dua atau lebih model dalam satu tampilan tanpa menggabungkannya dalam kelas yang berisi keduanya.

Menggunakan Karyawan sebagai model contoh:

@model Employee

Sebenarnya diperlakukan seperti.

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

Jadi metode View (karyawan) menyetel model Anda ke ViewBag dan kemudian ViewEngine mentransmisikannya.

Artinya,

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

Bisa digunakan seperti,

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

Pada dasarnya, Anda dapat menggunakan apa pun yang ada di ViewBag Anda sebagai "Model" karena bagaimanapun cara kerjanya. Saya tidak mengatakan bahwa ini secara arsitektural ideal, tetapi mungkin saja.

Alex Tselevich
sumber
3

Buat saja Model tampilan tunggal dengan semua informasi yang diperlukan di dalamnya, biasanya yang saya lakukan adalah membuat model untuk setiap tampilan sehingga saya bisa spesifik pada setiap tampilan, baik itu atau membuat model induk dan mewarisinya. ATAU buat model yang menyertakan kedua tampilan tersebut.

Secara pribadi saya hanya akan menambahkannya ke dalam satu model tetapi begitulah cara saya melakukannya:

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)
}
Michael
sumber
1

Anda dapat menggunakan pola presentasi http://martinfowler.com/eaaDev/PresentationModel.html

Model "View" presentasi ini dapat berisi Person dan Order,
kelas baru ini dapat menjadi model referensi tampilan Anda.

James Kyburz
sumber
1
Model presentasi harus benar-benar berisi data yang dibutuhkan, yang mungkin berasal dari Person dan Order. Seharusnya tidak berisi objek domain Person atau Order. Tampilan memisahkan tampilan dari domain yang mendasarinya.
Fenton
0

Cara lain yang tidak pernah dibicarakan adalah Membuat tampilan di MSSQL dengan semua data yang ingin Anda sajikan. Kemudian gunakan LINQ ke SQL atau apa pun untuk memetakannya. Di pengontrol Anda, kembalikan ke tampilan. Selesai.

tersembunyi
sumber
0

Anda tidak dapat mendeklarasikan dua model pada satu tampilan, coba gunakan Html.Action("Person", "[YourController]")& Html.Action("Order", "[YourController]").

Semoga berhasil.

Jimmy Mac
sumber
Apa fungsinya?
johnny
0

Selain satu model tampilan di asp.net Anda juga dapat membuat beberapa tampilan parsial dan menetapkan tampilan model yang berbeda untuk setiap tampilan, misalnya:

   @{
        Layout = null;
    }

    @model Person;

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

kemudian model tampilan parsial lainnya untuk model pesanan

    @{
        Layout = null;
     }

    @model Order;

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

lalu di tampilan utama muat kedua tampilan parsial dengan

<partial name="PersonPartialView" />
<partial name="OrderPartialView" />
Shojaeddin
sumber
-1

Saya harap Anda merasa terbantu !!

saya menggunakan ViewBag Untuk Proyek dan Model untuk tugas jadi dengan cara ini saya menggunakan dua model dalam tampilan tunggal dan dalam pengontrol saya mendefinisikan nilai atau data viewbag

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
            });

dan dalam tampilan tbltask dan projectlist adalah dua model diff saya

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} Daftar @model

Muhafil Saiyed
sumber