选择最近的相关记录

时间:2013-09-08 08:34:00

标签: java hibernate postgresql

我想按如下方式实施产品定价:

  • Product对象包含一个描述其当前价格的Pricing对象。
  • Product表链接到一对多关系中的Pricing表
+------------+             +---------------------+
| 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。这样我就会知道客户在购买时为产品支付的费用。

此数据还可用于尚未定义的会计和其他数据挖掘活动。

3 个答案:

答案 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)

如果我要从当时总结我自己的发现(我也在设计购物软件,即使我的问题是将其作为与博客相关的内容):

  1. 有效查询当前行与历史行的最佳方法(imho)是将后者存储在单独的审计表中(即价格与price_revs)。这样可以回避看起来很多的低效查询,并在面向客户的用例中保持快速和简化。

    审计表应适当更新,理想情况但不一定使用触发器。 (如果对您很重要,我最终选择了tsrange类型而不是两个单独的start_date / created_at和end_date / deleted_at字段。)

  2. 警惕过于热心的外键限制,特别是如果你引入级联删除。删除产品时,您可能仍希望保留产品及其定价历史记录。如果是这样,您需要删除状态或标记或您选择的任何内容。从某种意义上说,您的主要参考点应该是修订版ID,而不是product_id或price_id。

  3. 如果您希望将实时行与同一产品的最新非实时行共存(例如,在建议的草稿定价得到某个随机经理验证的情况下进行实时定价),我发现更好的解决方案是创建一个单独的价格(具有草稿状态)。将它想象成一个新的“当前”草案分支,à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 pricesproduct相关联的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

如果您将新价格添加到价目表中,则根据“可达性持续性”,此新价格将变为持久价格。无论是在原始实例是持久的还是在内存状态与数据存储同步之前,从持久性实例可到达的所有对象都会变为持久性。