【问题标题】:Entity framework - calculate sum field from child records实体框架 - 从子记录计算总和字段
【发布时间】:2018-05-03 07:58:33
【问题描述】:

我正在使用带有 ASP.NET Core 的实体框架核心,代码优先。

在我的应用程序中,我有发票,具有典型的 InvoiceHeader -> InvoiceLine 关系。 InvoiceLine 实体有一个 LineAmount 字段,当显示为列表时,我想对其求和并显示在 InvoiceHeader 上(这样我可以在查看发票列表时看到发票总额)。

我猜我需要将TotalAmount 属性添加到InvoiceHeader 实体,并带有注释[NotMapped]。但是如何最有效地填充它呢?

目前我的InvoiceHeaderController.Index() 是:

    // GET: InvoiceHeaders
    public async Task<IActionResult> Index()
    {
        ApplicationUser appUser = ConstantData.GetApplicationUser(_context, _userManager.GetUserId(User));
        var applicationDbContext = _context.InvoiceHeader.Include(i => i.Customer).Include(i => i.CustomerBranch)
            .Where(i => i.CustomerID == appUser.CustomerID);
        return View(await applicationDbContext.ToListAsync());
    }

谁能告诉我计算(求和)这个TotalAmount 属性的最有效方法是什么?

谢谢。

【问题讨论】:

  • 您的数据模型不应包含该属性。使用视图模型。您可以使用 linq .Sum() 来获取总数。
  • InvoiceLine 中有 Line Amount 字段,并且 InvoiceHeader 中已有一个 CustomerID 字段。您必须在 Invoiceheader 控制器中根据客户填充 Line 金额的总和吗?
  • @StephenMuecke:实际上,这取决于。有时预先计算总量并将其存储在“标题”中很有用 - 当您不需要详细信息时,检索速度会更快。有时这可用于验证数据完整性(某种审计)。当然,这也有它的缺点。
  • @Saneeshkunjunni:CustomerID 在这里并不重要。这只是这张发票所针对的客户的 ID。一个客户可以有多张发票,在这种情况下,一个客户的每张发票会有不同的总数
  • @StephenMuecke:谢谢。我会试试的。

标签: c# asp.net asp.net-mvc entity-framework entity-framework-core


【解决方案1】:

选择 sum 作为单独的字段,您需要创建新的模型类,如下所示

public class InvoiceHeaderModel{
   public InvoiceHeader invoiceHeader{get;set;}
   public decimal TotalAmount {get;set;}
}

并做出改变

// GET: InvoiceHeaders
public async Task<IActionResult> Index()
{
    ApplicationUser appUser = ConstantData.GetApplicationUser(_context, _userManager.GetUserId(User));
    var applicationDbContext =await _context.InvoiceHeader.Where(i =>i.CustomerID == appUser.CustomerID).ToListAsync();
    var data = applicationDbContext.Aggregate( new List<InvoiceHeaderModel>(),(invoiceHeaderModellist, it)=>{ invoiceHeaderModellist.Add(new InvoiceHeaderModel(){ InvoiceHeader =it,TotalAmount  = it.InvoiceLine.Sum(t=>t.LineAmount)}); return invoiceHeaderModellist;});
    return View(data);
}

在此操作中,我认为您不需要包含“Include(i => i.Customer).Include(i => i.CustomerBranch)”,如果需要,您可以在 where 关闭之前添加。

【讨论】:

  • 谢谢。我会试试这个。
  • 无法正常工作。似乎填充 applicationDbContext 的代码行使用单个 InvoiceHeaderModel 填充它,而不是任何类型的列表,因此 ToListAsync() 方法不会编译,因为单个对象不能转换为列表。
  • 嗨@Shaggs 我编辑了 InvoiceHeaderModel 列表试试这个.. 并更新
  • 可能您需要将异步任务更改为普通任务..并删除 return View(applicationDbContext);
  • 嗨@shaggs async 任务问题已解决,请检查
【解决方案2】:

我设法解决了。 Saneesh 的建议很接近,但不是我想要的。

我最终使用的代码是:

// GET: InvoiceHeaders

public async Task<IActionResult> Index()
{
    ApplicationUser appUser = ConstantData.GetApplicationUser(_context, _userManager.GetUserId(User));
            var applicationDbContext = _context.InvoiceHeader.Include(i => i.Customer).Include(i => i.CustomerBranch)
                .Where(i => i.CustomerID == appUser.CustomerID)
                .Select(i => new InvoiceListViewModel
                {
                    invoiceHeader = i,
                    TotalAmount = i.InvoiceLines.Sum(t => t.LineAmount)
                });
    return View(await applicationDbContext.ToListAsync());
}

感谢您的帮助,萨尼什。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 1970-01-01
    • 2014-10-13
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    相关资源
    最近更新 更多