1

我正在使用以下应用程序结构在 C# 中开发 N 层应用程序。

我的解决方案结构。

  1. UI - WPF Prism 和 ViewModels 连接到服务。由商店员工使用。
  2. 服务 - WCF - 业务逻辑、数据检索和通过数据层连接到数据库。
  3. 实体 - EF POCO 实体 - 没有逻辑。
  4. 数据 - EF DbContext 和 EDMX - 数据库连接
  5. Web - ASP.NET MVC 应用程序 - 基于 Web 的 UI 版本,具有有限的功能和客户访问权限。连接到服务。

我想知道在哪里可以找到具有计算的实体对象的逻辑。

这是示例实体。

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 自动计算行项目的总计(我可以将其设为数据库中的计算列),并计算发票的小计、折扣、税款、总计。我假设在这种情况下,如果我想在内部调用CalculateTotals(),例如当SalesTax 更改而不是将其留给客户端调用CalculateChanges 时,我可能必须删除自动属性。那是对的吗?如果是,那么我将 EF 模板重构为不具有自动属性,而是具有支持字段的属性,这将成为一个问题。

请告知哪种方法更好,为什么?或者针对这种情况采用完全不同的方法。谢谢你的帮助。

4

1 回答 1

1

我们的工具中有一个类似的问题,并将计算放在域对象本身中。一个对象应该知道它的总数的原因是因为它知道它的孩子。我们的服务层中使用的业务逻辑特定于业务规则而不是计算。这是我们的代码示例(注意:我们使用 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 总是知道自己的 Subtasks,所以计算应该总是正确的。

于 2013-04-15T20:08:20.240 回答