2014-09-01 52 views
2

我有一个名为'JobTitle'的EF实体类型,它具有一个名为'Offices'的导航属性(这是另一个名为'Office'的实体类型的集合)。如何在MVC中显示来自导航属性集合的值索引页

我想在我的索引视图中显示JobTitle名称和相关Office名称的列表。 观脚手架生成默认的情况如下:

@model IEnumerable<Example.Models.JobTitle> 

@{ 
    ViewBag.Title = "Index"; 
} 

<h2>Index</h2> 

<table> 
    <tr> 
     <th> 
      @Html.DisplayNameFor(model => model.JobTitleName) 
     </th> 

    </tr> 

@foreach (var item in Model) { 
    <tr> 
     <td> 
      @Html.DisplayFor(modelItem => item.JobTitleName) 
     </td> 

    </tr> 
} 

</table> 

我的控制器代码(默认)看起来像:

// GET: /JobTitle/ 

    public ActionResult Index() 
    { 
     return View(db.JobTitles.ToList()); 
    } 

这将让我产生一切简单的属性属于' JobTitle'(如'JobTitleName')。不过,我无法弄清楚如何从“办公室”集合(导航属性)中检索相应的“办公室”信息到我的视图中。

因此,我希望最终显示两列'JobTitle'和'Office'。

(在我的数据库,这些实体是由三个表表示:JOBTITLE(JobTitleID,JobTitleName),办公室(OfficeID,OfficeName)和JobTitleOffice(JobTitleID,OfficeID))

我完全新的MVC和Entity Framework ,所以任何帮助感激地收到。

谢谢!

回答

4

今后,像这样的问题,它,如果你发布你的实际实体类是最好的。但是,根据您的表格,看起来您在JobTitleOffice之间存在多对多关系。您的困难很可能与如何访问特定JobTitle实例的OfficeName属性有关,并且存在的问题不仅仅是一个OfficeName,而是很多。您需要遍历Office s的列表。

<td> 
    @Html.DisplayFor(modelItem => item.JobTitleName) 
    @foreach (var office in item.Offices) 
    { 
     @Html.DisplayFor(m => office.OfficeName) 
    } 
</td> 

如果你想有一个稍微好一点的显示器,您可能希望打开办公室的名称为逗号分隔的列表(例如:,Office Name 1, Office Name 2, ...),它可以通过执行以下操作,而不是使用foreach来实现:

<td> 
    @Html.DisplayFor(modelItem => item.JobTitleName) 
    @string.Join(", ", item.Offices.Select(m => m.OfficeName)) 
</td> 

或者,如果你只关心呈现一个办公室的名称,你可以使用FirstOrDefault拉出一个办公室:

<td> 
    @Html.DisplayFor(modelItem => item.JobTitleName) 
    @{ 
     var office = item.Offices.FirstOrDefault(); 
     if (office != null) 
     { 
      @Html.DisplayFor(m => office.OfficeName); 
     } 
    } 
</td> 

您应该经常检查null首先,以防万一实际上没有相关的办公室。

基本上,您选择哪种方法取决于您的应用程序的要求。另外,请注意实体框架延迟加载相关项目。这里并没有那么糟糕,因为第一次尝试访问Offices时,将发出一个新的查询来获取相关的办公室。因为你并没有试图访问Office以外的任何相关属性,所以一个额外的查询不会有太大的影响。但考虑到以下几点:

public class Office 
{ 
    ... 

    public virtual Address Address { get; set; } 
} 

如果你试图做这样的事情:

@foreach (var office in item.Offices) 
{ 
    @office.OfficeName 
    <address> 
     @office.Address.Street 
     ... 
    </address> 
} 

你最终用什么所谓的N + 1个查询,在那里你有一个查询来获取集合(Offices)然后一个查询取Address每个办公室(导致N查询,其中N是办事处总数)。在这种情况下,你最好是急于加载。例如,

return View(db.JobTitles.Include("Offices.Address").ToList()); 

,会导致实体框架做了一个连接以包括每个Office实例都Offices每个Address所有查询来获取职称。然后,您可以使用任何此类信息做任何您想要的,而无需担心发出多个附加查询。

+0

谢谢克里斯,非常有帮助的解释。 – Martin 2014-09-02 08:05:55

0

您可以使用SelectManySelect将结果投影到JobTitleNameOfficeName的集合中。

<table> 
    <tr> 
     <th>@Html.DisplayNameFor(model => model.JobTitleName)</th> 
     <th>Office</th> 
    </tr> 

    @{ 
     var items = Model 
      .SelectMany(j => j.Offices 
       .Select(o => new { j.JobTitleName, o.OfficeName })); 
    } 
    @foreach (var item in items) { 
     <tr> 
      <td>@Html.DisplayFor(modelItem => item.JobTitleName)</td> 
      <td>@Html.DisplayFor(modelItem => item.OfficeName)</td> 
     </tr> 
    } 
</table> 

PS

Offices集合将自动被加载(执行的foreach时),如果你对导航性能virtual关键字,并使用默认配置(代理+延迟加载)。这被称为延迟加载。

public class JobTitle 
{ 
    // other properties 
    public string JobTitleName { get; set; } 
    public virtual ICollection<Office> Offices { get; set; } 
} 
public class Office 
{ 
    // other properties 
    public string OfficeName { get; set; } 
    public virtual ICollection<JobTitle> JobTitles { get; set; } 
} 

更多