数据访问层中的计算

Posted

技术标签:

【中文标题】数据访问层中的计算【英文标题】:Calculations In Data Access Layer 【发布时间】:2014-01-30 14:13:05 【问题描述】:

我正在使用 n 层方法将大型 Classic ASP Web 应用程序转换为 ASP.Net MVC。在我的 DAL 中,我使用 ADO.Net 来查询数据库并将查询转换为对象。我还有一个用于计算和验证之类的 BLL。

我的问题涉及在需要计算以将查询转换为对象时在 DAL 中执行计算。举个例子,考虑一个带有摘要信息和行项目的发票系统:

public class Invoice

    public int InvoiceID  get; set; 
    public DateTime InvoiceDate  get; set; 
    public decimal InvoiceTotal  get; set; 
    public List<InvoiceLineItem> LineItemList  get; set; 

所以我在数据库查询中转换行项目的代码如下所示:

decimal InvoiceTotal = 0;
var LineItem = new InvoiceLineItem();
while (Reader.Read())

    LineItem.ItemID = Extensions.SafeGetInt(Reader, "ItemID");
    LineItem.Price = Extensions.SafeGetDecimal(Reader, "Price");
    LineItem.Quantity = Extensions.SafeGetInt(Reader, "Quantity");
    LineItemList.Add(LineItem);

    InvoiceTotal = InvoiceTotal + (LineItem.Price * LineItem.Quantity);    


Invoice.InvoiceTotal = InvoiceTotal;
etc ...

所以这是我的问题:考虑到我的 n 层架构,我的 DAL 是否适合执行 InvoiceTotal 计算?考虑到 BBL 的部分工作是执行计算,这是否违反了 DAL 和 BLL 之间的关注点分离?或者我是否过于从字面上理解了 BBL 执行计算的功能,如果需要这些计算来填充模型,可以在 DAL 中进行计算?我发现在 DAL 中进行 InvoiceTotal 计算很有吸引力的一个原因是因为我只需对发票项目记录进行一次迭代。如果我在其他地方创建了一个单独的 InvoiceTotal 函数来获取 InvoiceTotal,那么我将不得不再次遍历记录。

编辑:事实证明,真正的问题不是 DAL 中是否应该允许计算,而是 InvoiceTotal 是否应该在我的模型中。从数据库规范化的角度来看,它不是必需的,因为可以从行项目计算总数。在这种情况下,InvoiceTotal 不应该在我的模型中,而应该在我的 ViewModel 中,在这种情况下,不需要在我的 DAL 中进行计算。出于性能原因,我可以忽略数据库规范化问题,并在我的模型中包含 InvoiceTotal,但如果是这种情况,我会将 InvoiceTotal 持久保存到数据库中,在这种情况下,在填充我的模型时不需要计算,因为我只需从中提取值数据库。

经验教训:如果我想在我的 DAL 中进行计算,我的模型可能存在缺陷。

【问题讨论】:

平均 CPU 每秒可能进行数百万次迭代。这不应该决定你的架构;计算属于业务层。 计算属于业务层。持久化和查询数据属于数据层。 CodeCaster,我也想保持干爽。如果我创建一个单独的函数来计算发票总额并再次迭代记录,我不违反 DRY 吗? 有趣的是,在讨论使用代码隐藏验证来自浏览器的用户输入时,没有人担心 BLL 和关注点分离。 【参考方案1】:

我会将计算添加到业务逻辑层

在将发票总额写入数据库之前,应在应用程序中提供发票总额的初始计算,因此您不希望检索记录时计算总额的唯一位置。

将它添加到业务逻辑层的另一个很好的理由是它可以从 DAL 返回的行数据中派生出来,这将使 DAL 层专注于写入和读取数据。这也将您的计算保存在一个地方。

但是,由于发票总额在发送后固定,您可能希望在首次保存时写入初始值,然后允许手动修改。在这种情况下,发票总额的计算将在业务层完成,但该值也将写入数据库并从数据库中检索,而无需重新计算。

【讨论】:

实际上,我认为我的错误是 InvoiceTotal 根本不应该在模型中,而只能在 ViewModel 中(例如 InvoiceViewModel)。从数据库规范化的角度来看,没有理由将 Invoice Total 保存到数据库中,因为它可以从行项目中计算出来。如果我决定不在我的模型中包含 InvoiceTotal,而只在我的 ViewModel 中使用它,那么很明显 InvoiceTotal 必须是一个单独的函数,因为它不会在 InvoiceModel 中。 我同意净发票总额。对于总额,计算将包含一些税收要素,这些要素将来可能会发生变化。在这种情况下,我肯定会将其写入数据库。 你得到了分数,因为你的回答让我看到我的模型有缺陷

以上是关于数据访问层中的计算的主要内容,如果未能解决你的问题,请参考以下文章

由 dbml 形成的数据访问层中的功能

数据访问层中标准 ORM 的替代方案是啥? [关闭]

在单独的数据访问和业务逻辑层中,我可以在业务层中使用实体框架类吗?

EntityManager 应该如何在一个很好的解耦的服务层和数据访问层中使用?

在旧版应用程序中混合现代数据访问

如何访问 OpsWorks ECS 层中的私有 Docker 存储库?