考虑Rails中的订单来建模库存

时间:2017-02-27 09:26:53

标签: ruby-on-rails postgresql activerecord calculated-columns

我正在使用Rails 5开发租赁市场应用程序。它的用户,产品和订单结构非常简单,产品属于用户,实际创建它们。

为了让用户管理其产品的“实时”库存,已创建StockMovement模型/表,参考用户,库存变化(正/负)和日期。通过这种方式,我们可以根据“用户准备提供的内容”来确定特定日期的特定产品的库存。通过对单个表/模型的简单查询,我们设法获得股票的“总和”,这恰好是产品的库存。

除此之外,我们需要考虑何时下订单并确认某个产品,导致需要在一段时间内从库存中减去该项目的数量。

目前,我们使用StockMovement模型中的查询计算股票,并使用StockMovement模型中的自定义select子句手动加入受订单影响的金额,该条款已经开始变得有点过分(我们甚至都不是beta) )。

我的问题是,你将如何实现这种Rails方式?我总是遇到这样的情况,理论上,至少考虑到关系数据库逻辑(我们使用Postgres),最好的事情是使用带有连接和计算字段的查询动态计算所有内容,但是当涉及到使用ActiveRecord实现它,除非您在模型A的select语句中重新定义该计算,否则无法在表A的查询中引用表B中的计算列,这正是我想要避免的。 / p>

到目前为止,我目前看到的选项是:

1-保持原样:在select语句中重复计算逻辑,以便访问“外部计算字段”

2-每次确认订单时在StockMovement表中创建一条记录,并从那里处理所有库存(不是理想的恕我直言,因为每次在订单中修改某些东西时都需要仔细更新)

3-我无法想到的潜在魔法(和正确)解决方案......

谢谢!

2 个答案:

答案 0 :(得分:4)

就个人而言,我认为将SQL与ActiveRecord 混合是的Rails方式。这是我最喜欢的AR之一:您可以在需要时注入原始SQL。您甚至可以使用scopes将其封装在封装的,可重复使用的方法中。例如,您可以定义添加select列的范围。

您还可以创建名为current_stocks的{​​{3}},每个产品只有一条记录。拥有该视图查询stock_movementsorders并计算当前库存,然后只需在需要该值时使用它。您甚至可以database view,这样您仍然可以使用常规关联,实例方法等。再次,Rails为您提供了一种方法,使高级SQL功能与您的应用程序的其余部分相得益彰。

如果您每次都在动态计算库存,最终会出现性能问题,因此您可以(1)将其设为 make a readonly ActiveRecord class backed by the view并在后台定期刷新或( 2)在current_stock上添加products列,并使其保持最新状态。我可能会选择2。

或者你可以(3)坚持实时计算但是添加一个starting_stocks表,它会给你一个“截至星期日午夜时的股票”值,这样你就不必计算太多了过去。我认为这可能是最好的方法,你可以推迟实施它,直到你遇到问题为止。

如果你真的想深入研究,你可能想要了解时态数据库。两本好书是Richard Snodgrass的在SQL中开发面向时间的数据库应用程序和Tom Johnston的 Bitemporal Data 。前者也可以从作者的网站上免费获得PDF。我猜你现在对你来说太过分了,但是知道它仍然是件好事。

答案 1 :(得分:2)

考虑在进行时缓存总数,并将其保存回数据库。它比总结所有历史记录的效率要高得多。

Rails有一个counter_cache的概念(更多信息:http://guides.rubyonrails.org/association_basics.html#options-for-belongs-to-counter-cache),但这只计算记录 - 而不是总计。

幸运的是还有 counter_culture gem,它允许你计算总数(见https://github.com/magnusvk/counter_culture#totaling-instead-of-counting

我不知道您是否已经拥有Stock个对象,但Stock has_many StockMovements StockPosition绝对是我的最佳选择。这样你仍然可以进行所有粒状运动;你的查询很快;并且您的计数器根据数据库事务的性质保持最新和准确。

编辑:我刚刚阅读了您的评论"我对特定日期的股票价值感兴趣" 。这并不一定会使此方法无效,但意味着您可能希望将其扩展为包含类似StockPosition记录的内容(可以每天创建),以记录任何给定日期的位置。这种方法是否有意义完全取决于您将如何查询数据,并且您可以采取多种方法,例如:查询一天Stock;将所有历史记录汇总到设定日期;或者从当前{{1}}总计中减去记录总和回到特定日期(比查询所有历史数据更有效,如果您查找的日期往往非常接近现在)。