I am creating a billing system管理每个客户的分类帐。每个Ledger都有一个LedgerEntry列表,用于记录每个客户交易。
当我测试这个时,我注意到如果我在同一个事务中创建了一堆LedgerEntry,那么@Id值不是为了将对象赋予em.persist(),除非我做了em。创建每个条目后刷新()。
因为我依赖于id的顺序来确定Ledger的正确行为(具体来说,当前的余额是列表中的最后一个LedgerEntry - 由@OrderBy强制执行“id ASC”),这意味着我有冲洗()很多次。
创建每一行后是否有办法避免刷新?也就是说,如何在不使用@OrderColumn的情况下对对象的持久性进行某种排序?
答案 0 :(得分:1)
我不确定这是通用的JPA还是Hibernate,但请注意Hibernate的persist()
和save()
之间的区别。来自the docs(强调我的):
persist()
使瞬态实例持久化。但是,它不保证标识符值将立即分配给持久性实例,分配可能在刷新时发生。- save()确保返回标识符。如果必须执行INSERT以获取标识符(例如“身份”生成器,而不是“序列”),则无论您是在事务内部还是外部,都会立即执行此INSERT。
因此,如果您使用save()
,则应按照您调用save()
的顺序生成ID。如果只是为了获取ID而执行插入是有问题的(对于性能等),您可以选择使用另一个不需要命中数据库的ID生成器。
答案 1 :(得分:0)
据我所知,没有关于语句的顺序和规范中EntityManager
方法调用的顺序。即使您的提供商允许通过某种专有设置进行配置,或者默认情况下提供此行为,我也不会依赖它。
但实际上,如果你需要处理有序列表,IMO会很有意义地使用列来维护持久性顺序并使用OrderColumn
来定义它。你应该IMO不要依赖PK来做生意。
答案 2 :(得分:0)
我不完全确定我理解你的结构。
您应该能够通过transaction_timestamp对单个业务事务(多个LedgerEntry行?)进行排序,以获得正确的顺序。
但为什么表中的当前余额行呢?它可以计算,是吗?
如果当前余额行有,我将创建一个line_item_number列,并为每个业务事务按顺序分配值。当与Ledger id结合使用时,这可能会成为一个很好的唯一键。并且我将当前余额行分配为999999的魔术值,因此它总是最后排序。
一个很好的副作用是从表中选择欠款真的很容易 - 对line_item_number = 999999的所有行求和。
然而,我的偏好是删除current_balance行,看看问题就消失了。
另一个选择是将计算机current_balance放在Ledger中,而不是将其作为LedgerEntry行。
答案 3 :(得分:0)
使用什么方法生成id?序列 ?桌子?用户指定的? 如其他回复所述,无法保证分配顺序但如果生成方法不依赖于数据存储区,那么大多数实现都会将调用时的值设置为“persist” ”。如果生成方法OTOH使用数据存储区,则您必须刷新以强制此数据存储区联系。