MVC两个控制器一个视图

本文关键字:一个 视图 两个 MVC 控制器 | 更新日期: 2023-09-27 18:21:18

我试图在一个现有的控制器中创建一个细节视图,该视图连接两个控制器并传递到视图中,但到目前为止我所尝试的一切都没有成功。我有4个数据模型,我想使用其中的2个公司和员工。因此,当我选择特定公司的详细信息时,它将在同一视图中返回与该公司相关的所有员工。

HRDataModel类

  public partial class HRDataModel : DbContext
{
    public HRDataModel()
        : base("name=HRDataModel")
    {
    }
    public virtual DbSet<Company> Companies{ get; set; }
    public virtual DbSet<Attribs> Attribs{ get; set; }
    public virtual DbSet<Staff> Staffs { get; set; }
    ....

公司数据模型

[Table("Company")]
public partial class Company
{
    public Company()
    {
        Staffs = new HashSet<Staff>();
    }
    public virtual ICollection<Staff> Staffs { get; set; }
    public int companyId{ get; set; }
    [Required]
    [StringLength(10)]
    public string companyName{ get; set; }
    .....

员工数据模型

public partial class Staff
{
    public Staff()
    {
        Skills = new HashSet<Skill>();
    }
    public virtual Company Company{ get; set; }
    public virtual ICollection<Skill> Skills { get; set; }
    public int staffId { get; set; }
    .........

我正试图在CompanyController中获取我的Details方法,以显示数据库中所有活跃公司的详细信息,以及该公司的所有员工

[Route("Company/Staff/1}")]
public ActionResult Details(int id)
{
    Company co = db.Companies.Find(id); 
    ...How to implement????           
    return View(bu);
}

如果有人能给我指明正确的方向,那就太好了。我试了又试,但什么都做不到?

MVC两个控制器一个视图

由于公司包括员工,因此可以使用include方法来包括相关实体。

var company = db.Companies.Include(c => c.Staffs).FirstOrDefault(x => x.id == companyId);
return View(company);

在你看来:

@foreach(var staff in Model.Staffs) { ... }

您需要将包含公司信息和员工详细信息的数据结构传递到视图中。您可以传递现有的Comapny实体类来执行此操作。但问题是,它使您的剃刀视图与ORM生成的实体紧密耦合。如果您明天将数据访问层切换到其他层,该怎么办。所以这个解决方案不太好。

因此,您应该使用一个视图模型(一个简单的POCO类),它具有需要在视图中渲染的属性。然后在操作方法中从数据库读取实体,将其映射到vie-wmodel实例并发送。

创建这样的视图模型。

public class CompanyInfo
{
  public int Id {set;get;}
  public string Name {set;get;}
  public List<StaffItem> Staffs {set;get;}
  public CompanyInfo()
  {
     this.Staffs = new List<StaffItem>();
  }
}
public class StaffItem
{
  public int Id {set;get;}
  public string Name {set;get;}
}

在您的操作方法中,读取公司实体并将其映射到视图模型

public ActionResult Details(int id)
{
    var vm = new ComapnyInfo();
    var company = db.Companies
             .Include(r => c.Staffs)
             .FirstOrDefault(x => x.companyId==id); 
    if(co!=null)
    {
       //Map the property values now
       vm.Name = co.companyName;
       vm.Id = co.companyId;
       if(co.Staffs!=null)
       {
         vm.Staffs = co.Staffs.Select(f=> new StaffItem {
                              Id=f.staffId,
                              Name = f.staffName}).ToList();
       }
    }       
    return View(vm);
}

现在,您的视图应该绑定到CompanyInfo视图模型

@model YourNamespace.CompanyInfo
<h2>@Model.Name</h2>
<h3>Staffs</h3>
@foreach(var staff in ModelStaffs)
{
  <p>@staff.Name</p>
}

如果你不喜欢手动映射,你可以考虑使用像Automapper这样的映射库。

Hi@stackface您不需要传递两个控制器来获得两个视图,您所做的是创建一个视图模型,它本质上是多个模型的容器,并将其从控制器传递到视图中。

例如,Model1、Model2、ModelN都是必需的,因此您有一个类,在该类中,它具有由Model1、Model2和Model3组成的属性,这样您就可以传入具有所有必需模型的类。

例如

public class Company{...}
public class Staff{...}
public class ViewModel{
public Company Company {get;set;}
public List<Staff> Staff{get;set;}
}
controller:
{
var viewModel = new ViewModel();
viewModel.Company = db.Companies.FirstOrDefault(x => x.id == companyId);
viewModel.Staff = db.Staff.Where(x => x.CompanyId == campanyId).ToList() //or whatever your properties are called.
Return View(viewModel);
}

更新视图以采用ViewModel类型。

您还可以通过调用返回部分视图的控制器操作来组成视图。

其优点是可以重用局部视图及其操作,例如在不同页面上以相同布局显示公司详细信息。这提高了一致性和可维护性。

缺点是您缺乏灵活性:如果某个页面需要不同的布局,您应该创建一个新的视图。性能也可能较低,因为您使用许多小操作而不是单个大操作访问后端。

显示公司和员工详细信息的组合视图模型只需要知道如何访问所需的数据:

public class CompanyAndStaffDetailsViewModel {
    public long CompanyId { get; set; }
    public long StaffId { get; set; }
}

以下操作将呈现组合视图:

public ActionResult Details(long companyId, long staffId) {
    var viewModel = new CompanyAndStaffDetailsViewModel {
        CompanyId = companyId,
        StaffId = staffId
    };
    return View("Details", viewModel);
}

"详细信息"视图通过调用呈现部分视图的操作组成用例:

@model CompanyAndStaffDetailsViewModel 
@Html.Action("CompanyInfoPartial", "Company", new { companyId = Model.CompanyId })
@Html.Action("StaffInfoPartial", "Staff", new { staffId = Model.StaffId })

"公司"控制器提供可重复使用的操作来呈现公司详细信息:

 public ActionResult CompanyInfoPartial(long companyId) {
       Company co = db.Companies.Find(companyId);
       var model = Mapper.Map<CompanyViewModel>(co); // map persistable entity to ViewModel
       return PartialView("_CompanyInfoPartial", model);
 }

则等价视图_CompanyInfoParital.cshtml只需要处理CompanyViewModel中存储的公司信息,而对Staff一无所知:

@model CompanyViewModel
@Html.DisplayFor(m => m.CompanyName)
// etc ...

StaffInfoPartial操作的思想与CompanyInfoPartial的思想相同。