我想按如下方式实施产品定价:
+------------+ +---------------------+ | Product | | Price | +------------+ 1-n +---------------------+ | product_id | ----------- | product_id | | ... | | price_id | +------------+ | price_value | | price_creation_time | | ... | +---------------------+
到目前为止听起来很简单,但我遇到麻烦的部分是
基本上,从Product对象中,关系应该看起来好像是一对一的关系。但是,我不知道如何使用Hibernate实现这样的东西
Last Record of one to many relation Hibernate Criteria建议一些名为Criteria的东西可能会有所帮助,但我的Hibernate经验很少,而且我仍在掌握类注释。
是否有可能实现一对多关系,这样与Hibernate似乎是一对一的关系?我该怎么做呢?
更新:关于这个想法的更多信息如下:
收据将包含每个购买商品的记录集合。
+--------------+ +------------------+ | Receipt | | ReceiptLine | +---------+ +--------------+ +------------------+ +----- | Product | | receipt_id | ----------- | receipt_id | | +---------+ | receipt_time | | product_id | -----+ +-------+ | ... | | price_id | ----------- | Price | +--------------+ | product_quantity | +-------+ | ... | +------------------+
产品的当前价格(显然只有一个当前价格)由价格表中具有最新时间戳的价格记录确定。
SELECT *
FROM prices
WHERE product_id = (Product ID goes here)
ORDER BY price_creation_time;
LIMIT 1;
当您更新定价时,我想要插入新的定价,而不是更新当前链接到产品的定价记录。
INSERT INTO price (
product_id,
price_value,
price_creation_time
) VALUES (
(Product ID goes here),
(New price goes here),
NOW()
);
当客户购买东西时,每条购买的商品的收据记录中都会添加一行。每行包含产品的ID,cut还包括生成收据时适用的定价记录的ID。这样我就会知道客户在购买时为产品支付的费用。
此数据还可用于尚未定义的会计和其他数据挖掘活动。
答案 0 :(得分:0)
实际上,最好的解决方案是从PRODUCT中获得明确的FK - > PRODUCT_PRICE。
优选:
<one-to-one name='currentPrice' class='ProductPrice' column='FK_CURR_PRICE'
fetch='join' />
您可以映射内部a以选择最近价格的ID,但它不具有高性能和强大的并发性。
间接,不是首选:
<one-to-one name='currentPrice' class='ProductPrice'>
<formula>
(select MAX(ID) from PRODUCT_PRICE where PRODUCT_PRICE.FK_PRODUCT=this.ID)
</formula>
</one-to-one>
答案 1 :(得分:0)
我认为你应该看看慢慢变化的尺寸:
http://en.wikipedia.org/wiki/Slowly_changing_dimension
你可能也会发现这个帖子很有趣,因为它与你正在做的事情高度相关,你几乎肯定会遇到类似于我自己问的情况:
Temporal database design, with a twist (live vs draft rows)
如果我要从当时总结我自己的发现(我也在设计购物软件,即使我的问题是将其作为与博客相关的内容):
有效查询当前行与历史行的最佳方法(imho)是将后者存储在单独的审计表中(即价格与price_revs)。这样可以回避看起来很多的低效查询,并在面向客户的用例中保持快速和简化。
审计表应适当更新,理想情况但不一定使用触发器。 (如果对您很重要,我最终选择了tsrange类型而不是两个单独的start_date / created_at和end_date / deleted_at字段。)
警惕过于热心的外键限制,特别是如果你引入级联删除。删除产品时,您可能仍希望保留产品及其定价历史记录。如果是这样,您需要删除状态或标记或您选择的任何内容。从某种意义上说,您的主要参考点应该是修订版ID,而不是product_id或price_id。
如果您希望将实时行与同一产品的最新非实时行共存(例如,在建议的草稿定价得到某个随机经理验证的情况下进行实时定价),我发现更好的解决方案是创建一个单独的价格(具有草稿状态)。将它想象成一个新的“当前”草案分支,àlagit ,当你不再需要时,它会被合并(即从“当前”行中删除)进入实时分支它
答案 2 :(得分:0)
- 产品只有一个有效价格,即最近一个。
- 不应提取最近一次之前的任何定价记录。
您可以使用Hibernate filters来实现此目的。这将允许您在不初始化整个集合的情况下检索集合的某些元素。在这种情况下,您只想从Price
类中的price collection
中提取一个Product
元素(最近的一个)。
将此过滤器定义添加到Product
映射文件中(首先使用<filter-def/>
元素中的<hibernate-mapping/>
元素定义过滤器,然后将过滤器附加到price
集合中:
<hibernate-mapping package="x.y.z">
<class name="Product" table="product_table_name">
....
<set name="priceList" inverse="true" cascade="save-update" lazy="true">
...
<filter name="priceFilter"
condition="price_id = (select max(p.price_id) from Price p where
p.product_id = product_id)" />
</set>
</class>
<filter-def name="priceFilter"/>
</hibernate-mapping>
此过滤器会使用max(price_id)加载price
,这是product
最近添加的价格。现在,您需要为给定会话启用此过滤器,可以按如下方式执行:
session.enableFilter("priceFilter");
为了确保您获得与最近Product
相关联的Price
,请在检索产品数据之前启用会话过滤器:
session.enableFilter("priceFilter");
Criteria criteria = session.createCriteria(Product.class);
criteria.setFetchMode("priceList", FetchMode.JOIN);
criteria.add(Restrictions.eq("id", productId));
Product product = (Product) criteria.uniqueResult();
使用此过滤器,关系将显示为一对一的关系。关联的价目表将只包含一个Price
(最近的一个)。如果您没有使用session.enableFilter("stateFilter")
启用过滤器,Hibernate将加载所有相关价格。
- 当用户编辑产品的定价时,不应更新当前记录,应插入带有当前时间戳的新记录 代替。
- 之前的定价记录是出于历史原因而保留的(例如,查看客户想要在产品上支付产品的退款 购买时间)。
假设您有set
prices
与product
相关联的updatePrice
,可以使用Product
中的private Set<Price> priceList = new HashSet<Price>();
...
public void updatePrice(Price price) {
price.setId(null);// Hibernate will execute an INSERT statement
price.setProduct(this);
priceList.add(price);
}
方法完成此操作} class:
Id
我们的想法是在将Price
添加到null
的{{1}}之前,将price
的{{1}}属性设置为priceList
如果您将新价格添加到价目表中,则根据“可达性持续性”,此新价格将变为持久价格。无论是在原始实例是持久的还是在内存状态与数据存储同步之前,从持久性实例可到达的所有对象都会变为持久性。