在n层c#应用程序中何处放置计算逻辑
本文关键字:何处放 计算逻辑 应用程序 | 更新日期: 2023-09-27 18:09:13
我正在用c#开发一个n层应用程序,使用下面的应用程序结构。
My Solution结构。
- UI - WPF Prism和ViewModels连接到服务。商店员工使用。
- Services - WCF - Business Logic, Data Retrieval and connection to DB through Data layer.
- 实体- EF POCO实体-无逻辑。
- 数据- EF DbContext和EDMX - DB连接
- Web - ASP。. NET MVC应用程序-基于UI的web版本,功能有限,客户访问权限有限。
我想知道在哪里有计算的实体对象的逻辑。
这是样本实体。
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 Total。在发票中添加行项目需要更改小计、税、折扣和总额。
我想知道我是否可以在服务层做到这一点,让实体贫血。我担心的是,我需要不断地在网络上来回发送整个发票对象。
尽管我还没有做移动解决方案,但我不确定这在移动环境中是否是个好主意,因为来回发送发票可能会消耗数据。
另一个想法,例如,我认为是在InvoiceDetail中有AddLineItem()方法,在Invoice中有CalculateTotals()。
AddLineItem自动计算行项目的total(这可以使其成为DB中的计算列),并计算发票的小计、折扣、税和total。我假设在这种情况下,如果我想在内部调用CalculateTotals(),例如当SalesTax发生变化时,而不是让客户端调用CalculateChanges时,我可能必须删除自动属性。对吗?如果是,这对我来说是一个问题,重构EF模板,使其不具有自动属性,而是具有支持字段的属性。
请告知哪种方法更好,为什么?或者是完全不同的方法。谢谢你的帮助。
在我们的工具中有一个类似的问题,并将计算放在Domain对象本身中。一个对象应该知道它的总数是因为它知道它的子对象。我们的服务层中使用的业务逻辑特定于业务规则,而不是计算。下面是我们的代码示例(注意:我们使用c#)。Net with 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总是知道它自己的子任务,所以计算应该总是正确的。