Dos modelos en una vista en ASP MVC 3


91

Tengo 2 modelos:

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

Quiero editar objetos de AMBAS clases en una vista ÚNICA, así que necesito algo como:

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

Esto, por supuesto, no funciona: solo se permite una declaración de 'modelo' en un archivo .cshtml. ¿Puede haber alguna solución?


1
¿Mi respuesta te ayuda?
Andrew

Usé ViewBagcon para cada vista que funcionó para mí, verifique esto para conocer varias opciones, me ahorró poco tiempo en lugar de crear un modelo de vista o una vista parcial
shaijut

Respuestas:


118

Cree un modelo de vista principal que contenga ambos modelos.

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

De esta manera, puede agregar modelos adicionales en una fecha posterior con un esfuerzo mínimo.


2
Cuando use esta solución, tenga en cuenta que los cambios en Model1 o Model2 pueden tener un efecto en su MainPageModel. También contienen más datos de los que la vista realmente necesita. Si su MainPage es una combinación de cosas que ya están en otros controladores, cambiar de RenderPartial a RenderAction le permitirá mantener las cosas perfectamente separadas. Considere leer sobre la Ley de Demeter: en.wikipedia.org/wiki/Law_of_Demeter
Fenton

1
@Andi: creé el modelo como sugirió anteriormente. Pero cuando hago clic derecho en el controlador e intento crear el controlador Crud, ¿no funciona? ¿Alguna sugerencia? ¿Cómo puedo crear un controlador crud con vista automática para el modelo anterior?
NoviceMe

2
De todos los enfoques que he visto para resolver este problema, este es el que mejor me ha funcionado. Es, con mucho, la solución más simple que funciona.
Ciaran Gallagher

4
El momento en el que te preguntas "¿Por qué no pensé en eso antes?" Gran solución
Rafael AMS

1
@Andi ¿Cómo expondría los métodos del modelo respectivo en el controlador?
Volatil3

53

Para usar la tupla, debe hacer lo siguiente, en la vista, cambie el modelo a:

@model Tuple<Person,Order>

para usar los métodos @html, debe hacer lo siguiente, es decir:

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

o

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

Item1 indica el primer parámetro pasado al método Tuple y puede usar Item2 para acceder al segundo modelo y así sucesivamente.

en su controlador necesita crear una variable de tipo Tuple y luego pasarla a la vista:

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

Otro ejemplo: varios modelos en una vista


1
Nunca use un Tupleen este caso: OP desea editar datos y Tupleno tiene un constructor predeterminado, por lo que el modelo no se puede vincular cuando se envía el formulario

Nunca digas nunca. Eso es un poco fuerte aquí.
johnny

47

Otra opción que no tiene la necesidad de crear un modelo personalizado es usar un Tuple <> .

@model Tuple<Person,Order>

No es tan limpio como crear una nueva clase que contenga ambos, según la respuesta de Andi, pero es viable.


en mvc 3 da error Solo se permite una declaración de 'modelo' en un archivo. ¿Alguna idea de cómo solucionarlo?
GibboK

1
@GibboK - Lo estoy usando en MVC3 muy bien. ¿Asegúrate de no tener dos @modellíneas separadas ?
Bobson

3
Puede obtener las propiedades de cada modelo con: @Model.Item1.Propertyy @Model.Item2.Propertypara Persony Orderrespectivamente
user2019515

1
He usado Tuple en mi vista. Pero no puedo obtener los valores del modelo en mi controlador. Pero, mientras uso el modelo de vista principal como lo recomendó @Andi, obtuve los valores del modelo en mi controlador.
Naren

1
@StephenMuecke - Hmm. Nunca lo había considerado, pero tienes razón. Otra razón por la que la respuesta de Andrew es la mejor de propósito general. Cuando vas con una alternativa de peso ligero (como éste), que no renuncia a la funcionalidad.
Bobson

10

Si eres fanático de tener modelos muy planos, solo para admitir la vista, debes crear un modelo específico para esta vista en particular ...

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

Mucha gente usa AutoMapper para mapear desde sus objetos de dominio a sus vistas planas.

La idea del modelo de vista es que solo admite la vista, nada más. Tiene una por vista para asegurarse de que solo contenga lo que se requiere para esa vista, no un montón de propiedades que desea para otras vistas.


5

ok, todo el mundo tiene sentido y tomé todas las piezas y las puse aquí para ayudar a los novatos como yo que necesitan una explicación de principio a fin.

Haces tu gran clase que tiene 2 clases, según la respuesta de @ Andrew.

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

Luego en tu controlador llenas los 2 modelos. A veces solo necesitas llenar uno. Luego, en la devolución, hace referencia al modelo grande y se llevará el 2 dentro a la Vista.

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

En la parte superior de la vista

@model yourNamespace.Models.teamBoards

Luego cargue sus entradas o pantallas haciendo referencia a los contenidos grandes de Modelos:

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

Y. . . .De vuelta en el rancho, cuando llegue el Post, haga referencia a Big Class:

 public ActionResult ContactNewspaper(teamBoards teamboards)

y hacer uso de lo que devolvieron los modelos:

string yourVariable = teamboards.Team.yourField;

Probablemente tenga algo de Validación de anotación de datos en la clase y probablemente ponga if (ModelState.IsValid) en la parte superior del bloque de guardar / editar. . .


4

De hecho, existe una forma de usar dos o más modelos en una vista sin envolverlos en una clase que contenga ambos.

Usando Employee como modelo de ejemplo:

@model Employee

En realidad se trata como.

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

Entonces, el método View (employee) establece su modelo en ViewBag y luego ViewEngine lo lanza.

Esto significa que,

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

Puede usarse como,

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

Esencialmente, puede usar lo que esté en su ViewBag como un "Modelo" porque así es como funciona de todos modos. No digo que esto sea ideal desde el punto de vista arquitectónico, pero es posible.


3

Simplemente cree un modelo de vista única con toda la información necesaria en él, normalmente lo que hago es crear un modelo para cada vista para poder ser específico en cada vista, ya sea eso o hacer un modelo principal y heredarlo. O haz un modelo que incluya ambas vistas.

Personalmente, simplemente los agregaría en un modelo, pero así es como lo hago:

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

Puede utilizar el patrón de presentación http://martinfowler.com/eaaDev/PresentationModel.html

Este modelo de presentación de "Vista" puede contener tanto Persona como Orden, esta nueva
clase puede ser el modelo que hace referencia a su vista.


1
El modelo de presentación debería contener realmente los datos requeridos, que pueden provenir de una Persona y una Orden. Realmente no debería contener los objetos de dominio Persona u Orden. La vista desacopla la pantalla del dominio subyacente.
Fenton

0

Otra forma de la que nunca se habla es Crear una vista en MSSQL con todos los datos que desea presentar. Luego use LINQ to SQL o lo que sea para mapearlo. En su controlador, devuélvalo a la vista. Hecho.


0

no puede declarar dos modelos en una vista, intente usar Html.Action("Person", "[YourController]")& Html.Action("Order", "[YourController]").

Buena suerte.


¿Qué hace esto?
johnny

0

Además de un modelo de vista en asp.net, también puede realizar múltiples vistas parciales y asignar diferentes vistas de modelo a cada vista, por ejemplo:

   @{
        Layout = null;
    }

    @model Person;

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

luego otro modelo de vista parcial para el modelo de pedido

    @{
        Layout = null;
     }

    @model Order;

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

luego, en su vista principal, cargue ambas vistas parciales por

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

-1

Espero que te sea de ayuda !!

uso ViewBag para proyecto y modelo para la tarea, así que de esta manera estoy usando dos modelos en una sola vista y en el controlador definí el valor o los datos de 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
            });

y en vista tbltask y projectlist son mis dos modelos de diferencia

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} @ Lista de modelos

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.