我目前正在尝试将遗留数据库模式(我无法轻易更改)映射到JPA 1.0(提供程序是 Hibernate 3.3)。该模式是在磁盘空间非常宝贵的时代设计的,因此有几种情况会将多个不同的值打包到二进制字节数组中。例如,给定以下三个枚举:
enum ItemA { A, B, C }
enum ItemB { E, F }
enum ItemC { G, H, I, J }
这些将被压缩成一个位串列,其中:
- 前 2 位编码
ItemA
(A = 0b01
,B = 0b10
,C = 0b11
), - 下一位是
ItemB
(0 = E
,1 = F
); 和 - 接下来的 2 位是
ItemC
(G = 0b00
,H = 0b01
,I = 0b10
, 和J = 0b11
)。
因此,为了映射它,我需要屏蔽每个位的范围,enum
然后将其映射到相应的值。
更糟糕的是,用于其中enum
每个值的实际位位置和掩码enum
会根据存储在数据库中的其他一些配置表而有所不同。唯一受支持的打包和解包这些值的方法是通过一组存储函数 (PL/SQL):
function pack_data(item_a in char(1), item_b in char(1), item_c in char(1)) returns raw...
function unpack_data_item_a(bit_string in raw) returns char(1) ..
function unpack_data_item_b(bit_string in raw) returns char(1) ..
etc
我当前的 JPA 映射如下所示:
@Entity
@Table(name = "some_table")
public class MyEntity {
@Id
@Column(name = "entity_id")
private Long id;
@Column(name = "bit_string")
private byte[] bitstring;
@Transient
private ItemA itemA;
@Transient
private ItemB itemB;
@Transient
private ItemC itemC;
...
}
问题是:如何enum
在加载时自动填充(解包)这些字段,然后在插入/更新时再次自动将它们打包到位串中?如果它们是只读的,那么我只需将它们隐藏在视图中并将它们映射为只读。
可能的解决方案讨论:
我考虑过使用@PrePersist
/@PreUpdate
生命周期回调,但 Hibernate 文档说不要EntityManager
在这些回调中触摸,这使得访问数据库有些困难。我可以添加一个新的持久性单元并使用REQUIRES_NEW
事务来访问生命周期回调中的存储过程,也许?这似乎有点骇人听闻。
可以通过 Hibernate 特定@SqlUpdate
/@SqlInsert
注释来覆盖 SQL 的解决方案吗?这似乎是可能的,但我害怕依赖 Hibernate 期望绑定变量出现的(有点随意的)顺序 - 这随着时间的推移是否稳定?
编辑:另一种可能性是使用视图进行读取并使用INSTEAD OF
触发器来填充位串。如果可能的话,我想避免这种情况,因为它对 JPA 是隐藏的,并且可能会使其他开发人员感到困惑。
任何帮助表示赞赏!