2017-04-26 78 views
1

我的查詢返回匹配特定位置的人員列表。我希望它能夠返回所有職位的列表,即使沒有人匹配職位。我加入人們的原因是因爲我需要「Assigned」的計數,這是一個與位置相匹配的動態添加計數字段。但是,如果有匹配誰,我希望它仍然返回駐紮位置的位置,但不想要的人「分配」設置爲0。LINQ返回MVC5上的所有記錄和groupby Razor查看

dynamic query = (from a in db.Positions 
        join b in db.People 
        on new { 
         a.GradeId, 
         a.SeriesId, 
         a.CompanyId, 
         a.PaybandId } 
        equals new { 
         b.GradeId, 
         b.SeriesId, 
         b.CompanyId, 
         b.PaybandId } into ab 
        from k in ab.DefaultIfEmpty() 
        join c in db.Grades on k.GradeId equals c.Id 
        join d in db.Series on k.SeriesId equals d.Id 
        join e in db.Companies on k.CompanyId equals e.Id 
        join p in db.Paybands on k.PaybandId equals p.Id 
        group a by new { CompanyName = e.Name, 
         GradeName = c.Name, 
         SeriesName = d.Name, 
         PaybandName = p.Name, 
         a.Authorized } into f 
        select new { Company = f.Key.CompanyName, 
         Grade = f.Key.GradeName, 
         Series = f.Key.SeriesName, 
         Payband = f.Key.PaybandName, 
         Authorized = f.Key.Authorized, 
         Assigned = f.Count() }).AsEnumerable().Select(r => r.ToExpando()); 

我面臨的另一個問題是,剃刀頁面上,該公司正在重複。我需要公司每個公司僅出現一次,但希望所有職位都列在其下。

這裏是查看截圖和剃刀腳本: Razor View Screenshot

@model IEnumerable<dynamic> 

@{ 
    Layout = "~/Views/Shared/_Layout.cshtml"; 
} 

<h2>@ViewBag.Title</h2> 
<table class="table table-responsive table-hover"> 
    <thead> 
     <tr> 
      <th class="col-sm-1"></th> 
      <th class="col-sm-2">Grade</th> 
      <th class="col-sm-2">Series</th> 
      <th class="col-sm-2">Payband</th> 
      <th class="col-sm-2">Authorized</th> 
      <th class="col-sm-2">Assigned</th> 
     </tr> 
    </thead> 
    @foreach (dynamic item in Model) 
    { 
     <thead> 
      <tr> 
       <th class="panel-bg" colspan="6">@item.Company</th> 
      </tr> 
     </thead> 
     <tbody> 
      <tr> 
       <td class="col-sm-1"></td> 
       <td class="col-sm-2">@item.Grade</td> 
       <td class="col-sm-2">@item.Series</td> 
       <td class="col-sm-2">@item.Payband</td> 
       <td class="col-sm-2">@item.Authorized</td> 
       <td class="col-sm-2">@item.Assigned</td> 
      </tr> 
     </tbody> 
    } 
</table> 

任何幫助,不勝感激!

EDIT(在請求添加Positions.cs類)

namespace CPR.Models 
{ 
using Newtonsoft.Json; 
    using System; 
    using System.Collections.Generic; 
    using System.ComponentModel.DataAnnotations; 
    using System.ComponentModel.DataAnnotations.Schema; 
    using System.Data.Entity.Spatial; 

    public partial class Positions 
    { 
     public Positions() 
     { 

     } 

     [Key] 
     public int Id { get; set; } 

     [Required] 
     public int CompanyId { get; set; } 

     [Required] 
     public int SeriesId { get; set; } 

     [Required] 
     public int GradeId { get; set; } 

     [Required] 
     public int PaybandId { get; set; } 

     [Required] 
     public int Authorized { get; set; } 

     public virtual Companies Companies { get; set; } 

     public virtual Series Series { get; set; } 

     public virtual Grades Grades { get; set; } 

     public virtual Paybands Paybands { get; set; } 
    } 
} 
+0

你可以添加你的職位類嗎? –

+0

@MichaelBurns - 根據您的請求添加 – Element808

回答

2

你需要稍微改變邏輯您查詢到更早計數,然後事情就會變得容易一點。請看下面的代碼片段中的註釋:

  ... 

      from a in db.Positions 
       join b in db.People 
       on new { 
        a.GradeId, 
        a.SeriesId, 
        a.CompanyId, 
        a.PaybandId } 
       equals new { 
        b.GradeId, 
        b.SeriesId, 
        b.CompanyId, 
        b.PaybandId } into ab 
       from k in ab.DefaultIfEmpty() 

       // you want to count the number of people per position here 

       group k by new { a.GradeId, a.SeriesId, a.CompanyId, a.PaybandId, a.Authorized } into g 
       select new { g.Key.GradeId, g.Key.SeriesId, g.Key.CompanyId, g.Key.PaybandId, g.Authorized, Count = g.Count(p => p != null) } into counts 

       // at this point you have position info AND people count per position 
       // next, you can do the remaining joins... 

       join c in db.Grades on counts.GradeId equals c.Id 
       join d in db.Series on counts.SeriesId equals d.Id 
       join e in db.Companies on counts.CompanyId equals e.Id 
       join p in db.Paybands on counts.PaybandId equals p.Id 

       // ... and select full data set, including person count, required for the view 

       select new { 
        CompanyName = e.Name, 
        GradeName = c.Name, 
        SeriesName = d.Name, 
        PaybandName = p.Name, 
        counts.Authorized, 
        Assigned = counts.Count 
       } into full 

       // one more step here that will help to tackle your second problem (grouping by company name in the view) 
       // you want your data coming into the view be grouped by company name 

       group full by full.CompanyName into groupByCompany 

       select new CompanyInfo { CompanyName = groupByCompany.Key, CompanyItems = groupByCompany.Select(i => new CompanyItem { GradeName = i.GradeName, SeriesName = i.SeriesName, PaybandName = i.PaybandName, Authorized = i.Authorized, Assigned = i.Assigned }).ToList() } 

       ... 

然後在視圖中,您將需要創建2個@foreach循環,而不是一個。第一,外部之一,將循環在上面的收集和呈現的公司名稱一排一次,而另一方面,內部一個,將在集合中的每個項目的CompanyItems財產環路和公司下呈現每件行名稱行。

此外,由於有多個thead標籤,它們是not allowed,因此您生成的HTML不是100%有效。以下是經過編輯的版本:

... 
@model IEnumerable<CompanyInfo> 

<table class="table table-responsive table-hover"> 
    <thead> 
     <tr> 
      <th class="col-sm-1"></th> 
      <th class="col-sm-2">Grade</th> 
      <th class="col-sm-2">Series</th> 
      <th class="col-sm-2">Payband</th> 
      <th class="col-sm-2">Authorized</th> 
      <th class="col-sm-2">Assigned</th> 
     </tr> 
    </thead> 
    @foreach (CompanyInfo item in Model) 
    { 
     <tbody> 
      <tr class="company-name"> 
       <th class="panel-bg" colspan="6">@item.CompanyName</th> 
      </tr> 
      @foreach (CompanyItem companyItem in item.CompanyItems) 
      { 
       <tr> 
        <td class="col-sm-1"></td> 
        <td class="col-sm-2">@companyItem.Grade</td> 
        <td class="col-sm-2">@companyItem.Series</td> 
        <td class="col-sm-2">@companyItem.Payband</td> 
        <td class="col-sm-2">@companyItem.Authorized</td> 
        <td class="col-sm-2">@companyItem.Assigned</td> 
       </tr> 
      } 
     </tbody> 
    } 
</table> 

... 

要使用強類型的視圖模式,添加這兩個類:

class CompanyInfo 
{ 
    public string CompanyName { get; set; } 
    public List<CompanyItem> CompanyItems { get; set; } 
} 

class CompanyItem 
{ 
    public string GradeName { get; set; } 
    public string SeriesName { get; set; } 
    public string PaybandName { get; set; } 
    public bool Authorized { get; set; } 
    public int Assigned { get; set; } 
} 

,然後更新代碼按照上述更新。

+0

令人驚歎的,徹底的答案。隨着你的實現,我收到了一些錯誤。 1.名稱'a'在當前上下文中不存在,2.'AnonymousType#1'不包含'Count'的定義。選擇新的{ 公司名稱= e.Name, GradeName = c.Name, SERIESNAME = d.Name, PaybandName = p.Name, a.Authorized,// <----錯誤1 分配=計數。 Count()// <---- error 2 }全部變爲 – Element808

+1

對不起,您是對的。修正它們,請參閱更新的代碼。基本上,'Assigned = counts.Count()'應該是'Assigned = counts.Count';對於'a.Authorized',它應該被包含到第一組中並且從那裏被重用。此外,請注意在視圖中使用'class =「company-name」'attr。自從我們擺脫了多個'thead's之後,需要用CSS對公司名稱行進行樣式設計。 – m1kael

+0

在視圖上最後一件事是用代碼替換頁面上的所有內容並傳遞到視圖@model IEnumerable 。我經歷了所有事情,並且在動態查詢中選擇了最終選項,它應該包含「CompanyName」,但是獲取錯誤:'object'不包含視圖上'CompanyName'的定義。有任何想法嗎? – Element808

-1

「我希望它返回所有位置的列表,即使沒有 人誰的位置相匹配。」

如你所說,你應該簡單地做下一個(編輯這一部分):

前:

from a in db.Positions 
join b in db.People 

後:

from a in db.Positions 
left join b in db.People 

正如你所看到的我申請了left join,因爲SQL LEFT JOIN返回左側的所有行表,即使右表沒有匹配。這意味着如果ON子句匹配右表中的0(零)記錄;該連接仍然會返回結果中的一行,但右表中的每列都有NULL。

這意味着左連接返回左表中的所有值,以及來自右表的匹配值,或者在沒有匹配連接謂詞的情況下返回NULL。

我希望這有助於你的, 乾杯

+2

「左連接」不是有效的LINQ語法,不幸的是,否則這將更簡單:) – Element808