因此,我一直在努力使自己熟悉JPA的继承功能,并且到目前为止,我真的很喜欢它们。最近发生在我身上的一件事是,它们实际上可以用于获取数据以外的其他用途。鉴于它可以基于鉴别值获得子类,因此继承实际上是将配置字段转换为实现的便捷方法。在我的知识与经验比率处于“刚好足以危险/不足以始终意识到它所在的区域”的阶段,我认为最好问一下这是否是一个好主意。
以PRODUCT和BILLTYPE表为例。
Product:
int Id
int billtypeid
Billtype:
int id
varchar[15] description
Billtype只是产品的计费策略(我们会说某些订单可能是按重量计费的,而其他订单可能只是根据情况计费的)。在开票过程中,每种账单类型都需要使用不同的方法。 Billtype表可能只有少数几个条目,并且不应增长到很大。
使用继承对抽象的Billtype实体进行子类化是否有意义,该实体还为发票代码所需的不同方法定义了一个接口?像这样:
@Entity
@DiscriminatorColumn("description")
public abstract class BillType {
// Getters, setters
// Abstract methods that could be used elsewhere - ex:
// BigDecimal calculateInvVal(...)
}
@Entity
@DiscriminatorValue("by case")
public class CaseBillType extends BillType {
// Implementation of calculateInvVal - now when invoicing code needs this method,
// the right one is always associated with the current product!
}
这提供了一种方便的方式来将行为与数据库中代表配置数据的字段相关联,但是却将业务代码与实体(大多数情况下非常顽皮)混合在一起。我可能会遇到一种设计模式来解决这个问题,但我真的很想避免不得不写很多东西,“如果这是票据类型,请获取此子类,如果这是票据类型,等等。” ”代码。
我从一个答案中寻找的是对该技术潜在缺陷的解释,我可能没有看到,这将为寻找该问题的另一种解决方案辩解。
最佳答案
如果可以在运行时添加,删除和修改账单类型而无需重建和重新部署应用程序的新版本,则将产品与BillType实体链接起来很有用。您的示例并非如此。
因此,如果您拥有一组静态的帐单类型,每个帐单类型都定义了一个由BillType子类封装的静态行为,则可以简单地使用BillType枚举。该枚举的每个实例定义自己的行为。您不需要为此使用实体层次结构和附加表。
用于计算Product实体中的InVal的代码将完全相同:
BigDecimal computeInVal() {
billType.calculateInVal(this);
}
获取所有账单类型的代码将是
return BillType.values();
而不是将代码类型与产品相关联的以下代码:
product.setBillType(em.find(BillType.class, ID_OF_CASE_BILL_TYPE));
你只会有
product.setBillType(BillType.BY_CASE);