【问题标题】:Group By and take first and last elements from the table in c# WPFGroup By并从c#WPF中的表中获取第一个和最后一个元素
【发布时间】:2020-07-06 02:51:23
【问题描述】:

我有一张名为 Invoices 的表格。我必须按 createdDate 分组并获取第一个和最后一个发票编号并将其显示为范围。除此之外,我还需要选择 createdDate 作为列之一。我正在使用实体框架,下面是我之前尝试过的代码。我是初学者,如果您能给我正确的解决方案,那就太好了。

MyContext.Invoices
         .Where(x => x.IsActive == true)
         .GroupBy( t=>
         {
            CreatedDate = DbFunctions.TruncateTime(t.CreationDate),
            InvoiceNumber = t.InvoiceNumber
         })
         .ToList()
         .Select(t => new ReportViewModel
         {
            DayDate = t.Key.CreatedDate.ToString(),
            TotalAmount = t.Sum(x => x.Price),
            InvoiceNumRange = t.Key.InvoiceNumber.First() + " - " + t.Key.InvoiceNumber.Last(),
            DisplayLabel = t.Key.CreatedDate.ToString()                              
         })
         .Where(d => (DateTime.Parse(d.DayDate) >= fromDate && DateTime.Parse(d.DayDate) <=  toDate))
         .OrderByDescending(o => o.DayDate)
         .ToList()

【问题讨论】:

    标签: c# wpf entity-framework


    【解决方案1】:

    首先:不要做中间 ToList。这将执行查询并获取所有数据。稍后您会丢弃一些获取的数据。让数据库做它可以做的所有选择,只将数据移动到需要的本地进程,并作为最后一条语句执行 ToList。

    我们不需要完整的发票,只需要一些值。

    DateTime fromDate = ...
    DateTime toDate = ...
    
    var result = myContext.Invoices.Select(invoice => new
    {
        CreatedDate = DbFunctions.TruncateTime(invoice.CreationDate),
        IsActive = invoice.IsActive,
        InvoiceNumber = invoice.InvoiceNumber,
        Price = invoice.Price,
    })
    

    只保留日期范围内的活动项目:

    .Where(invoice => invoice.IsActive
                   && fromDate <= invoice.CreatedDate
                   && toDdate >= invoice.CreaedDate)
    

    从剩余的项目中,将具有相同值CreatedDate 的组分组。 使用带有参数 resultSelector 的 IQueryable.GroupBy 的重载。

    我不确定实体框架是否知道字符串处理方法,所以我将选择需要的数据作为日期时间,然后再将其传输到本地内存。

    .GroupBy(invoice => invoice.CreatedDate,       // groups with same value for CreatedDate
    
    // parameter resultSelector: take the createdDate, 
    // and all invoices that have this createdDate to make one new ReportViewModel
    (createdDate, invoicesWithThisCreatedDate) => new
    {
        DayDate = createdDate,
        TotalAmount = invoicesWithThisCreatedDate.Select(invoice => invoice.Price).Sum(),
        FirstInvoiceNumber = invoicesWithThisCreatedDate
                             .Select(invoice => invoice.InvoiceNumber)
                             .Min(),
        LastInvoiceNumber = invoicesWithThisCreatedDate
                             .Select(invoice => invoice.InvoiceNumber)
                             .Max(),
        })
    

    我假设InvoiceNumber 是一个数字。如果没有,你不能使用MinMax,你必须OrderBy / OrderByDescending 并取第一个元素。

    现在您已将数据限制在最少,您可以将剩余数据移至本地进程:

    .AsEnumerable()
    

    现在它在你的本地进程中,你可以使用字符串处理方法和其他本地方法:

    .Select(fetchedItem => new ReportViewModel
    {
        DayDate = fetchedItem.CreatedDate.ToString(),
        TotalAmount = fetchedItem.TotalAmount,
        InvoiceNumRange = String.Format("{0} - {1}", fetchedItem.FirstInvoiceNumber,
                                                     fetchedItem.LastInvoiceNumber),
    
        DisplayLabel = fetchedItem.CreatedDate.ToString(),
    })
    

    最后:全部执行:

    .ToList();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-01
      • 1970-01-01
      • 2016-06-05
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      相关资源
      最近更新 更多