数据处理和转换应该在哪里进行?

Where should data processing and transformation happen?

我正在使用 Angular 4 作为我的前端框架,基本上只是 asp net core 作为一个 API 客户端从中获取数据,偶尔 post 数据.

我正在制作一个仪表板来显示一些统计数据。我在数据库中的数据不能直接用于此仪表板,因为它需要转换和进一步处理。我不是 return 将模型实体连接到 API 而是一个 View Model ,它与删除了一些 id 等的模型实体基本相同

我现在拥有的是我的 Angular DashboardComponent 正在使用 DataService 构建一个指向我已经存在的 API 的 HTTP GET 请求]端点GetOrders。这将从数据库中获取所有订单并将其 return 发送到 DataService 并最终发送到 DashboardComponent 然后需要提取数据并进行大量处理和转换以便数据准备就绪提供给 Google Charts 并且可以生成有意义的图表。然后用户可以选择在仪表板上查看另一个图表,这不足以让 Orders 但还必须从数据库中检索另一个实体,因此使用不同的端重复上述 API 调用点.

我的问题归结为:

总的来说,我正在寻找一些关于此的设计模式或最佳实践,但还没有真正找到一些东西。

这不是应该使用什么设计模式的问题,而是遵循最佳实践的问题。以我有限的经验,应该尽可能避免在客户端进行数据处理和转换。 要回答您的第二个问题,是应该在客户端过滤数据还是将过滤条件传递给后端。这取决于几个因素:

  • 数据大小
  • 您将对数据应用的过滤器类型

如果您的数据很大,您可能希望避免在后端提取整个数据并过滤数据,否则您可能希望在客户端本身过滤数据。

  • 最好是在服务器端完成所有的处理和转换,return数据到几乎准备好呈现的客户端,还是离开有这个任务的客户?

    首选服务器端处理和转换。这样,如果您的对象 model/entities 发生变化,则可以使客户端不知道发生了什么变化。还有更多的原因,但应该是其中一个更大的原因。

  • 在服务器端处理和转换的情况下,我是否应该以 API 端点与我想在仪表盘?因此,例如选择 "Orders in the last 3 months in the UK" 会向 API 端点发送请求,该端点专门采用国家和时期等参数?

    你必须根据你要处理的用例来决定这一点,并在性能考虑和可重用性之间取得平衡(例如,你应该选择一种方法 return 具有大量数据的大对象或 return 具有最少数据的小对象的多个方法)。这里没有明确的规则。

  • 也许数据应该已经是我可以通过某种数据仓库用于仪表板的形状?这是解决这个问题的方法吗?

    这里也没有明确的规则。数据规模和预算将决定这一点。您可以在您的 .net 核心项目中使用 .Net 代码来调整您的数据,或者您可以拥有一个可扩展 PB 级数据的海量数据仓库……根据您的用例,这两种答案都是完全有效和荒谬的答案。

一般 "gut-check" 可以帮助您确定将什么放在哪里的东西...

  • 您希望您的视图具有尽可能接近于零的数据相关计算,您视图中的所有逻辑都应该是特定于视图的

    例如

    • 可以查看: 如果有内容 true/false 隐藏 this/that 并禁用 this/that

    • 属于视图之外: order_tax = tax_rate_for_state * 总数;

  • 如果其他人想要编写一个视图来显示您所做的统计繁重工作,您当前的 api(asp.net 控制器方法)是否会隔离编写视图的人从知道什么额外的观点?是的,这是您应该努力的目标。例如如果 iPhone 应用程序调用您的 api GetOrderTotal(orderNumber),则该 iPhone 应用程序不应知道您的折扣结构。

  • 当您使用控制器方法 return 生成整形结果时,用于整形数据的代码是否位于一个位置?在一个区域完成一些工作,在不同区域完成一些工作只会让调试变得更加困难。您不希望发生的一个例子是

    [HttpGet]       
    public double GetOrderTotal(string orderNumber)
    {
        // lets pretend here that we have a stored proc that returns an orderTotal
        var orderTotal = _orderService.GetOrderTotalUsingStoredProc(orderNumber);
    
        // this if else if block should be pushed at to the _orderService method 
        // or the OrderTotal stored procedure, otherwise any other code that relies
        // on _orderService.GetOrderTotalUsingStoredProc might not know that discounts
        // are applied to certain threshold amounts
    
        if (orderTotal > 1000)
        {
            orderTotal = orderTotal * 0.9
        } 
        else if (orderTotal > 10000)
        {
            orderTotal = orderTotal * 0.85
        }
    
        return orderTotal;
    }