在LINQ中检索具有货币转换复杂性的未结发票

时间:2017-04-14 13:42:18

标签: c# entity-framework linq

在我的Entity Framework应用程序中,我有一个名为Invoice.cs的实体,它有各种属性,但以下是我们关注的问题:

public class Invoice : IEntity
{
  public int Id { get; set; }
  public decimal Amount { get; set; }
  public DateTime Date { get; set; }
  public int OrderId { get; set; }
  public virtual ICollection<Payment> Payments { get; set; }
}

我正在尝试查询数据库以获取所有未结发票的列表。未结清的发票如下:

  

如果针对发票的付款总额 小于发票金额,则发票 Outstanding

如果发票在我的LINQ查询中未完成,我就会坚持不懈地工作,目前看起来像这样:

var outstandingInvoices = from inv in _context.Invoices
    where !inv.IsDeleted && inv.Date >= startDate && inv.Date <= endDate
    select inv;

startDateendDate是传入的参数,用于过滤结果。

与此相关的另一个复杂因素是如何进行付款。付款可以用人民币(中国货币)或英镑(英国货币)支付,在我生成的报告中,我希望所有都显示为GBP。

所以我必须以某种方式添加这个逻辑:

// loop through payments for each invoice, and add payment
// amount to a local variable called total
if (payment.Currency == Currency.Gbp)
{
  total += payment.Amount;
} else
{
  total += payment.Amount / (decimal)payment.ConversionRate;
}

Payment.cs实体具有以下两个值得关注的属性:

public class PaymentViewModel
{
  public int Id { get; set; }
  [Required]
  public decimal Amount { get; set; }
  [Required]
  [Display(Name = "Payment Currency")]
  public Currency Currency { get; set; }
  [Display(Name = "Conversion Rate")]
  public float ConversionRate { get; set; }
}

2 个答案:

答案 0 :(得分:1)

如果不在GBP中,您可以使用三元运算符来调整付款金额:

var outstandingInvoices = 
       from inv in _context.Invoices
       let totalPayment = inv.Payments.Sum(p => 
               p.Currency == Currency.Gbp ? p.Amount : p.Amount / p.ConversionRate)
       where !inv.IsDeleted 
          && inv.Date >= startDate && inv.Date <= endDate                
          && totalPayment < inv.Amount
       select inv;

答案 1 :(得分:1)

由于浮动/小数差异,您将遇到问题。根据您的数据库提供程序,它可能允许您强制从十进制转换为浮点数(或者可能不会)。当然,那么你会收到非常接近但不完全相同的付款问题。如果金额/ CoversionRate为0.999999999999999999999999999英镑,当金额为1英镑时怎么办?从技术上讲,它没有全额支付。

最终,转换率也应该是小数,而不是浮点数,但确定精度取决于您的来源。它精确到5位小数或7位?

var outstanding = _context.Invoices
  .Where(x=>x.Date >= startDate)
  .Where(x=>x.Date <= endDate)
  .Where(x=>!x.IsDeleted)
  .Where(x=>x.Payments.Sum(p=>(float)p.Amount / p.ConversionRate) < x.Amount);

或者,如果支付的总金额在1英镑以内:

var outstanding = _context.Invoices
  .Where(x=>x.Date >= startDate)
  .Where(x=>x.Date <= endDate)
  .Where(x=>!x.IsDeleted)
  .Where(x=>x.Payments.Sum(p=>(float)p.Amount / p.ConversionRate) - x.Amount < 1);