简体   繁体   中英

ASP.NET MVC Pass Multiple Models to View From Controller

I need to have a view that displays Employee First and Last Name and the Employees associated Supervisor First and Last name.

I have 2 models they are as follow:

public class Employee
{
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Department { get; set; }
    public int SupervisorID { get; set; }

    public virtual ICollection<Supervisor> Supervisor { get; set; }
}

public class Supervisor
{
    public int SupervisorID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
    public string Department { get; set; }

    public virtual Employee Employee { get; set; }
}

To display the needed data I have created another model:

public class EmployeeSupervisor
{
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Department { get; set; }

    public string SupFirstName { get; set; }
    public string SupLastName { get; set; }
    public string SupPhone { get; set; }
    public string SuoEmail { get; set; }
    public string SupDepartment { get; set; }
}

and in the details action of a controller I do the following:

Employee employee = db.Employees.Find(id);
Supervisor supervisor = db.Supervisors.Find(employee.SupervisorID);

EmployeeSupervisor es = new EmployeeSupervisor
{
    EmployeeID = employee.EmployeeID,
    Department = employee.Department,
    FirstName = employee.FirstName,
    LastName = employee.LastName,
    SupFirstName = supervisor.FirstName,
    SupLastName = supervisor.LastName,
    SuoEmail = supervisor.Email,
    SupPhone = supervisor.Phone,
    SupDepartment = supervisor.Department
};

return View(es);

Then in the view I have

@model TimeOffV3.Models.EmployeeSupervisor

and then lastly I do the following in the view

@Html.DisplayFor(model => model.FirstName)
@Html.DisplayFor(model => model.LastName)
@Html.DisplayFor(model => model.SupFirstName)
@Html.DisplayFor(model => model.SupLastName)

When I accomplish this task as described above with the EmployeeSupervisor model class, entity framework creates a corresponding table for EmployeeSupervisor in the database (as expected). This leads me to believe I'm doing it the wrong way as I can't imagine everytime I want to display data from 2 different models I need to create a new corresponding model and table.

Is the way I accomplished this correct? Should I be able to access the supervisor information using the navigation property defined in the Employee class? Can I pass in multiple models so I don't have to create a model containing the info from 2 separate models?

Indeed view receive only one model but this model doesn't have to be flat. Your view model could contain separate properties for each one of the entities

public class EmployeeSupervisor
{
    public Employee Employee { get; set; }
    public Supervisor Supervisor{ get; set; }
}

And in your view you work with them as following:

   @Html.DisplayFor(model => model.Employee.FirstName)
   @Html.DisplayFor(model => model.Employee.LastName)
   @Html.DisplayFor(model => model.Supervisor.FirstName)
   @Html.DisplayFor(model => model.Supervisor.LastName)

Additional thing that you should know, is that Views don't have to work with entities (those that have corresponding tables in the database). You can create a ViewModels that will contain only the properties that are used in your view. There are some libraries that can help you with mapping between ViewModels and entities, for example Automapper or ValueInjecter

If for example you need to display in your view only full names of employee and supervisor your view model could look like:

public class EmployeeSupervisorViewModel
{
    public string EmployeeName { get; set; }
    public string SupervisorName { get; set; }
}

And the controller:

    Employee employee = db.Employees.Find(id);
    Supervisor supervisor = db.Supervisors.Find(employee.SupervisorID);

    var model = new EmployeeSupervisorViewModel
    {
        EmployeeName =  string.Format("{0} {1}",employee.FirstName, employee.LastName),
        SupervisorName =  string.Format("{0} {1}",supervisor.FirstName, supervisor.LastName),
    };

    return View(model);

EmployeeSupervisorViewModel is not an entity and should not have a database table It is used only on View/Controller level and contains only the information that is required by View (info that you want to render to the client)

Look into ViewModels .

You have the right idea, but the problem is you shouldn't be creating another table with that view model.

Make sure your EmployeeSupervisor class is outside of your Entity Framework stuff, this class is strictly there to display data that corresponds to a view.

To answer your question

Is the way I accomplished this correct?

No, what you are looking for is View Models. Rachel Appel has an excellent post regarding this that I strongly recommend you read - Use ViewModels to manage data & organize code in ASP.NET MVC applications .

What are View Models?

ViewModels allow you to shape multiple entities from one or more data models (in your case this would be Employee and Supervisor) or sources into a single object, optimized for consumption and rendering by the view. - Rachel Appel

In other words it's just another simple class just like Employee and Supervisor often referred to as a POCO .

public class EmployeeSupervisorViewModel
{
    public int EmployeeId { get; set; }
    public string Department { get; set; }
    public string FristName { get; set; }
    public string LastName { get; set; }
    public string SupFirstName { get; set; }
    public string SupLastName { get; set; }
    public string SupEmail { get; set; }
    public string SupPhone { get; set; }
}

This allows you to do the following in your Controller

        var employee = _db.Employee.Find(id);
        var supervisor = _db.Supervisor.Find(employee.SupervisorID);

        var model = new EmployeeSupervisorViewModel()
        {
            EmployeeId = employee.EmployeeId,
            Department = employee.Department,
            FristName = employee.FirstName,
            LastName = employee.LastName,
            SupFirstName = supervisor.FirstName,
            SupLastName = supervisor.LastName,
            SupEmail = supervisor.Email,
            SupPhone = supervisor.Phone
        };
        return View(model);

In your View simply accept the View Model, EmployeeSupervisorViewModel, as the model and operate on it as before.

@model TimeOffV3.Models.EmployeeSupervisorViewModel

In the long run this mapping can be a bit tedious with larger View Models. This is where AutoMapper comes in handy.

Lastly I'd also recommend reading this post from Jimmy Bogard (How we do MVC – View models) it has some really good points on how to do View Models such as having a 1:1 mapping of the View and View Model and more.

Create a view model class that wraps employee and supervisor objects as properties. Do this outside of your EF model.

Pass an instance to your view having populated the properties through EF and access the properties to get the values.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM