1

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

  • Product 对象包含一个描述其当前价格的 Pricing 对象。
  • Product 表以一对多关系链接到 Pricing 表
+------------+ +------------+
| 产品 | | 价格 |
+------------+ 1-n +------------+
| 产品编号 | ------------ | 产品编号 |
| ... | | price_id |
+------------+ | 价格价值 |
                           | price_creation_time |
                           | ... |
                           +----------+

到目前为止听起来很简单,但我遇到的问题是

  • 该产品只有一个有效价格,即最近的一个。
  • 不应获取最近一次之前的任何定价记录。
  • 当用户编辑产品的定价时,不应更新当前记录,而应插入具有当前时间戳的新记录。
  • 保留以前的定价记录是出于历史原因(例如,在购买产品时看到客户想要退款)。

从本质上讲,在 Product 对象中,关系应该看起来好像是一对一的关系。但是,我不知道如何使用 Hibernate 来实现这样的事情

一对多关系 Hibernate Criteria 的最后记录表明,称为 Criteria 的东西可能会有所帮助,但我对 Hibernate 的经验很少,并且仍在掌握类注释。

是否有可能实现一对多的关系,就像与 Hibernate 这样的一对一关系?我该怎么做呢?

更新:关于这个想法的更多信息如下:

收据将包含所购买的每件商品的记录集合。

+--------------+ +------------------+
| 收据 | | 收据行 | +----------+
+--------------+ +-----------------+ +----- | 产品 |
| 收据_id | ------------ | 收据_id | | +----------+
| 收据时间 | | 产品编号 | -----+ +--------+
| ... | | price_id | ------------ | 价格 |
+--------------+ | 产品数量 | +-------+
                             | ... |
                             +------------------+

产品有一个当前价格(显然只有一个当前价格),该价格由价格表中具有最新时间戳的价格记录确定。

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。这样我就可以知道客户在购买产品时为产品支付的费用。

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

4

3 回答 3

0

实际上,最好的解决方案是从 PRODUCT -> PRODUCT_PRICE 中获得明确的 FK。

首选:

<one-to-one name='currentPrice' class='ProductPrice' column='FK_CURR_PRICE' 
    fetch='join' />

您可以在 a 中映射 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>
于 2013-09-08T11:37:17.763 回答
0
  • 该产品只有一个有效价格,即最近的一个。
  • 不应获取最近一次之前的任何定价记录。

您可以通过使用Hibernate 过滤器来实现这一点。这将允许您在不初始化整个集合的情况下检索集合的某些元素。在这种情况下,您只想从类中的当前元素中获取一个Price元素(最近的元素)。price collectionProduct

将此过滤器定义添加到您的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>

此过滤器将加载pricemax(price_id) ,这是最近添加的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 将加载所有关联的价格。

  • 当用户编辑产品的定价时,不应更新当前记录,而应插入具有当前时间戳的新记录。
  • 保留以前的定价记录是出于历史原因(例如,在购买产品时看到客户想要退款)。

假设您有 a与特定set的关联,这可以通过类中的便捷方法如下完成:pricesproductupdatePriceProduct

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);
}

这个想法是在将更新添加到的之前设置的Id属性。PricenullpricepriceListproduct

如果您在价目表中添加新价格,则此新价格将根据“可达性持久性”成为持久性。当原始实例被持久化或内存状态与数据存储同步之前,从持久化实例可访问的所有对象都变为持久化的。

于 2013-09-09T09:29:19.183 回答
0

我认为您应该研究缓慢变化的维度:

http://en.wikipedia.org/wiki/Slowly_changeing_dimension

您可能还会发现这个线程很有趣,因为它与您正在做的事情高度相关,而且您几乎肯定会遇到与我自己问的情况类似的情况:

时间数据库设计,有一个转折(实时与草稿行)

如果我要尝试总结一下我当时的发现(我也在设计购物软件,尽管我的问题将其介绍为与博客相关):

  1. 有效查询当前行与历史行的最佳方法(恕我直言)是将后者存储在单独的审计表中(即 price 与 price_revs)。这允许回避看起来血腥和低效的查询,并在面向客户的用例中保持快速和简化。

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

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

  3. 如果您希望实时行与同一产品的最新非实时行共存(例如,在建议的草稿定价由一些随机经理验证的同时进行实时定价),我发现更好的解决方案是完全创建一个单独的价格(具有草稿状态)。将其完全视为一个新的“当前”草稿分支,à la git,当您不再需要它时,它会被合并(即并从“当前”行中删除)到活动分支中。

于 2013-09-08T12:23:11.600 回答