我正在使用以下应用程序结构在C#中使用N层应用程序。
我的解决方案结构。
我想知道在哪里有一个有计算的实体对象的逻辑。
这是Sample实体。
public class Invoice
{
public int InvoiceID { get; set; }
public DateTime InvoiceDate { get; set; }
public Decimal SubTotal { get; set; }
public Decimal? SalesTax { get; set; }
public Decimal? DiscountPercent { get; set; }
public Decimal? DiscountAmount { get; set; }
public decimal Total { get; set; }
public ICollection<InvoiceDetail> InvoiceDetails { get; set; }
}
public class InvoiceDetail
{
public int InvoiceDetailID { get; set; }
public int InvoiceID { get; set; }
public Decimal Quantity { get; set; }
public Decimal Price { get; set; }
public decimal Total { get; set; }
public Invoice Invoice { get; set; }
}
在上面的场景中,我应该在何处放置逻辑以在值更改时计算发票总额。例如,SalesTax更新后需要更改发票总额。在发票中添加订单项需要更改小计,税金,折扣和总计。
我想知道我是否可以在服务层执行此操作并让实体陷入贫血。我所关心的是我需要不断地将整个发票对象来回发送。
即使我还没有使用移动解决方案,也不确定在移动环境中这是否是一个好主意,因为来回发送Invoice可能会消耗数据。
另一个想法是,例如,我想在InvoiceDetail中使用AddLineItem()方法,在Invoice中使用CalculateTotals()。
AddLineItem会自动计算订单项的总计(这可能会使其成为数据库中的计算列)并计算发票的小计,折扣,税金,总计。我假设在这种情况下,如果我想在内部调用CalculateTotals(),例如当SalesTax更改而不是将其留给客户端调用CalculateChanges时,我可能必须删除自动属性。那是对的吗?如果是,那么对于我来说,重构EF模板不具有自动属性而不是具有支持字段的属性会成为一个问题。
请告知哪种方法更好,为什么?或者对于这种情况采用完全不同的方法。谢谢你的帮助。
答案 0 :(得分:1)
我们的工具中有一个熟悉的问题,并将计算放在Domain对象本身。原因是一个物体应该知道它的总和是因为它知道它的孩子。我们的服务层中使用的业务逻辑特定于业务规则而非计算。这是我们的代码示例(注意:我们使用C#.Net和MVC3):
public class Task : DomainBase
{
public virtual ICollection<Subtask> Subtasks { get; set; }
[Display(Name = "Subtask(s) Total Cost")]
[DisplayFormat(DataFormatString = "{0:0.00}", ApplyFormatInEditMode = true)]
//calculated property
public virtual double TotalSubTaskCost
{
get
{
if (Subtasks == null)
return 0;
if (!Subtasks.Any())
return 0;
double it = Subtasks.Where(a => a != null).
Aggregate<Subtask, double>
(0, (current, a) => current + a.TotalCost);
return it;
}
}
}
每当查询Task的TotalSubtaskCost时,它都会执行计算。每个子任务都有自己的属性TotalCost。因此,我们对子子任务的这些值进行聚合和求和。由于Task始终知道自己的子任务,因此计算应始终正确。