2017-08-12 23 views
-3

我有一个MVC/ASP.NET Web应用程序跟踪员工信息,如StartDate,这是一个DateTime数据类型,员工在公司工作。Linq:按日期间隔分组(5,10,15等..年)

我们还在公司为员工颁发时间奖,并希望在公司中分5,10,15,20,25,30年以上。

我该如何编写一个Linq声明,该声明将仅由在公司时间已达到年度间隔基准(5,10,15等等)中的员工(人员)进行分组, “时间在公司”奖?谢谢你的帮助。

+1

你需要证明你已经尝试一下,提供一些示例代码。你有没有搜索过答案,因为我确信之前有人问过这个问题? – DavidG

+0

@DavidG - 我一直在找东西,并没有找到一个解决方案。我发现的那些是专门用于SQL(并且无法转换为linq),或者不适用于以前设置的静态时间间隔。我唯一的示例代码是查询数据上下文以获取在公司内部活动的人员(!EndDate.HasValue),以及由StartDate分组。我之前做过很多分组,之前没有这样的设置数据。 – Element808

+0

@Nkosi - 遗憾的是,我的情况略有不同,因为我只想要一个专门针对那些适合那个年份的人的专属查询。不是所有的人。 – Element808

回答

1

查看以下用于演示如何按期间/间隔进行分组的单元测试。

[TestClass] 
public class GroupByDateIntervalsTests { 
    [TestMethod] 
    public void Group_By_5_year_Intervals_Max_30() { 
     var employees = GenerateRandomDates(DateTime.Now, 5, 40, 50).Select((d, i) => new { id = i, StartDate = d }); 

     var now = DateTime.Today; 
     var period = 5; 
     var maxPeriod = 30; 
     var groups = from employee in employees 
        let interval = DateTime.MinValue.AddDays((now - employee.StartDate).TotalDays).Year/period 
        group employee by Math.Min(interval * period, maxPeriod) into g 
        orderby g.Key 
        select new { 
         period = g.Key, 
         employees = g.Select(e => e.id).ToArray() 
        }; 

     var result = groups.ToList(); 
    } 

    [TestMethod] 
    public void Group_By_Random_Interval_Max_30() { 
     var employees = GenerateRandomDates(DateTime.Now, 5, 40, 50).Select((d, i) => new { id = i, StartDate = d }); 

     var now = DateTime.Today; 
     var periods = new[] { 5, 10, 20, 30 }; 
     var groups = employees 
      .GroupBy(employee => { 
       var period = DateTime.MinValue.AddDays((now - employee.StartDate).TotalDays).Year; 
       var interval = periods.Where(p => (period/p) > 0).Max(); 
       return Math.Min(interval, periods.Max()); 
      }) 
      .Select(g => new { 
       period = g.Key, 
       employees = g.Select(e => e.id).ToArray() 
      }); 

     var result = groups.ToList(); 
    } 

    public List<DateTime> GenerateRandomDates(DateTime rootDate, int minAgeAtRootDate, int maxAgeAtRootDate, int count) { 
     Contract.Assert(minAgeAtRootDate <= maxAgeAtRootDate, "invalid age range. Minimum age cannot be higher than maximum age"); 
     var minDate = rootDate.Date.AddYears(-maxAgeAtRootDate); 
     var maxDate = rootDate.Date.AddYears(-minAgeAtRootDate); 
     var range = (maxDate - minDate).Days; 
     if (range == 0) { 
      range = 364; 
     } 
     var random = new Random(); 
     var dates = Enumerable 
      .Range(1, count) 
      .Select(i => minDate.AddDays(random.Next(range))) 
      .ToList(); 
     return dates; 
    } 
} 
1

这个解决方案非常棒!通过您的解决方案,我掌握了您的主要逻辑,并进行了一些改变,我认为其他人可能从中受益。绝对不可能以你的耐心来帮助你,并且我的专业知识与我正在努力完成的事情无关。

请参阅以下我的变化...

控制器

public ActionResult LengthOfService() 
{ 
    ViewBag.Title = "Length of Service Awards Report"; 
    var people = db.People.ToList().Where(p => !p.EndDate.HasValue); 
    var now = DateTime.Today; 
    var period = 5; 
    var maxPeriod = 30; 
    var query = (from p in people 
       let interval = DateTime.MinValue.AddDays((now - p.LengthOfService).TotalDays).Year/period 
       where interval > 0 
       group p by Math.Min(interval * period, maxPeriod) into x 
       orderby x.Key 
       select new AwardInfo 
       { 
        Years = x.Key, 
        People = x 
       }).ToList(); 
    return View(query); 
} 

视图模型

public class AwardInfo 
{ 
    public int Years { get; set; } 
    public IEnumerable<People> People { get; set; } 
} 

查看

@model List<CPR.Models.AwardInfo> 

<h2>@ViewBag.Title</h2> 

<table class="table table-responsive table-hover"> 
    <thead> 
     <tr> 

      <th class="col-sm-1">Service Award</th> 
      <th class="col-sm-2">Name</th> 
      <th class="col-sm-2">Date of Service</th> 
      <th class="col-sm-2">Company</th> 
     </tr> 
    </thead> 
    @foreach (var item in Model) 
    { 
     <tbody> 
      <tr> 
       <th class="panel-bg" colspan="5">@item.Years years</th> 
      </tr> 
     </tbody> 
     <tbody> 
      @foreach (var person in item.People) 
      { 
       <tr> 
        <td class="col-sm-1"></td> 
        <td class="col-sm-2">@person.LastName, @person.FirstName</td> 
        <td class="col-sm-2">@person.LengthOfService.ToShortDateString()</td> 
        <td class="col-sm-2">@person.Companies.Name</td> 
       </tr> 
      } 
     </tbody> 
    } 
</table> 

enter image description here