使用键java.time.YearMonth的JPA/Hibernate映射
我正在处理一个财务应用程序,其中时间单位为月,计划为(年,月)。FTT代表,给一点上下文 我们公司提倡干净数据库优先的方法。我们使用Hibernate5.1。我知道这是下线,但不能改变 我目前正在重构一个实体使用键java.time.YearMonth的JPA/Hibernate映射,java,hibernate,jpa,Java,Hibernate,Jpa,我正在处理一个财务应用程序,其中时间单位为月,计划为(年,月)。FTT代表,给一点上下文 我们公司提倡干净数据库优先的方法。我们使用Hibernate5.1。我知道这是下线,但不能改变 我目前正在重构一个实体 @Entity @Table(name="FTT_REPORT") public class FttReport { @Column(name="REPORT_ID") private final Long id = null;
@Entity
@Table(name="FTT_REPORT")
public class FttReport {
@Column(name="REPORT_ID")
private final Long id = null;
@Column(name="REFERENCE_YEAR")
private int referenceYear; //Old code, I could use YearMonth directly
@Column(name="REFERENCE_MONTH")
private int referenceMonth; //Old code, I could use YearMonth directly
private BigDecimal [a lot of tax figures];
@ElementCollection(fetch = FetchType.EAGER)
@MapKeyClass(YearMonth.class)
@OrderBy("REFERENCE_YEAR, REFERENCE_MONTH")
// @MapKeyType(@Type(type = "com.acme.FttYearMonthUserType")) #I'll explain soon why it's commented out
@AttributeOverrides({//
@AttributeOverride(name = "key.year", column = @Column(name = "REFERENCE_YEAR")),//
@AttributeOverride(name = "key.month", column = @Column(name = "REFERENCE_MONTH")),//
})
@CollectionTable(//
name = "FTT_REPORT_ADJUSTMENTS",//
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "FK_FTT_ADJUSTMENT_REPORT"),//
joinColumns = @JoinColumn(name = "REPORT_ID")//
)
private final SortedMap<YearMonth, FttAdjustment> adjustments = new TreeMap<>();
}
@实体
@表(name=“FTT\U报告”)
公共类FttReport{
@列(name=“REPORT\u ID”)
私有最终长id=null;
@列(名称=“参考年”)
private int referenceYear;//旧代码,我可以直接使用YearMonth
@列(name=“REFERENCE\u MONTH”)
private int referenceMonth;//旧代码,我可以直接使用YearMonth
私人大十进制[许多税收数字];
@ElementCollection(fetch=FetchType.EAGER)
@MapKeyClass(YearMonth.class)
@订购人(“参考年,参考月”)
//@MapKeyType(@Type(Type=“com.acme.FttYearMonthUserType”)#我很快会解释为什么它会被注释掉
@属性溢出({//
@AttributeOverride(name=“key.year”,column=@column(name=“REFERENCE\u year”)//
@AttributeOverride(name=“key.month”,column=@column(name=“REFERENCE\u month”)//
})
@收集表(//
name=“FTT\U报告调整”//
foreignKey=@foreignKey(value=ConstraintMode.CONSTRAINT,name=“FK\U FTT\U调整报告”)//
joinColumns=@JoinColumn(name=“REPORT\u ID”)//
)
私有最终分类映射调整=新树映射();
}
fttajustment
只是一个只包含数字列的可嵌入程序
一个简短的解释。我们的应用程序每月计算纳税报告,但有时出现延迟交易,客户必须向政府支付罚款/附加税。我们不会将该数字并入总税额,但需要向用户显示所有“调整”月份的所有附加税的完整报告
此时,我知道我可以通过使用LocalDate
作为映射键并假设day始终是第一天来命名它
但我必须先尝试更干净的方法
通过上述映射,以下操作是成功的:
- Hibernate使用我喜欢的正确列正确创建数据库创建脚本(没有
)@MapKeyType
- Hibernate成功添加了预期的主键和外键约束(无
)@MapKeyType
- Hibernate成功地
s单元测试的第一次税务调整我在Hibernate中看到了非常相似的映射,但有一个重要的区别:映射键映射到单个列。我在文档中找不到证据,但对于INSERT
关联,恐怕无法使用映射到多个列的map key进行类似映射 然而,我能够为@ElementCollection
协会做这件事。因此,下面我将提供一个例子 假设我们有以下模式:@OneToMany
我们可以使用以下映射:创建表FTT\U报告 ( 报告ID int不为空, 主键(报表ID) ); 创建表FTT\U报告\U调整 ( REPADJ_ID int不为空, REPADJ_报告_ID int不为空, 重漆, 重新油漆, 主键(REPADJ_ID), 外键(REPADJ\u REPORT\u ID)引用FTT\u REPORT(REPORT\u ID) );
@实体 @表(name=“FTT\U报告”) 公共类FttReport { @身份证 @列(name=“REPORT\u ID”) 私人长id; @OneToMany(级联=级联类型.ALL) @订购人(“重新订购年,重新订购月”) @JoinColumn(name=“REPADJ\u REPORT\u ID”,updateable=false) @映射键(name=“adjYearMonth”) 私有分类地图调整; } @实体 @表(name=“FTT\U报告调整”) 公共类FTTAD调整 { @身份证 @列(name=“REPADJ_ID”) 私人长id; //这只需要添加新的FTTA调整 @列(name=“REPADJ\u REPORT\u ID”) 私有长报告ID; @类型(Type=“com.acme.FttYearMonthUserType”) @列(列={ @列(name=“REPADJ_YEAR”), @列(name=“REPADJ_月”) }) 私人年月调整年月; }
注释只能在@MapKey
为实体时使用FttAdjustment
已添加到updateable=false
中,以避免在插入新的@JoinColumn
时进行额外的更新查询fttajustment
- 使用hibernate
5.4.10.Final对该映射进行了测试
另请注意,还有一个补充说明。
@AttributeOverride
是JPA为列名定义的注释,但您尝试使用它来设置列的列名。恐怕这是个错误。如何实现com.acme.FttYearMonthUserType
?查看ComponentType
的代码,Hibernate似乎试图实例化一个空的“container”对象来代替null
,因此出现了错误(另外,您是否碰巧启用了Hibernate.create_empty_composites.enabled
?此设置似乎触发了该行为)@crizzis否,我没有启用该属性。我有一个日志,其中显示了所有有效的Hibernate属性。我将发布用户类型,asapI已经看到Jadira框架为310个类型实现了映射器。我可以从它们的实现中复制/获取灵感,看看它是否有效。此外,我还可以尝试CompositeUserType1,我在实现中发现的一个问题是isMutable()
方法YearMonth
是不可变的,因此将true
切换到false
可能会使Hibernate不愿意实例化它。不确定这是否有帮助,但值得一试