2015-12-21 79 views
1

我有一个场景,我有2个标签需要配置。标签的名称是“Out Date”和“In Date”。数据库中只有一个名为'Date'的字段。无论是“Out”还是“In”,在运行时由Enum'Scenario'的值决定。但是,我需要实际显示用户输出日期& In Date,以便他可以选择1或两者。我听说JPA将为此提供计算领域概念。这是真的还是有其他方式可以实现这一点。以下是一些示例代码。计算属性与JPA。这是否适用于我的情况?

日期

@Override 
@Convert("DateTimeConverter") 
@Column(name = "DATE") 
public DateTime getDate() { 
    return date; 
} 

情景

@Override 
@Convert("EnumConverter") 
@Column(name = "SCENARIO") 
public Scenario getScenario() { 
    return scenario; 
} 

方案是与值的任何枚举OUT(1),IN(2)

+0

你好,你终于找到了一个适当的解决你的问题? –

回答

2

有在JPA没有计算性能。

您可以使用@Transient注解来创建不持续,但基于其他领域的计算性能:

@Transient 
public DateTime getInDate() { 
    if (scenario == Scenario.IN) { 
     return date; 
    } 
    return null; 
} 

@Transient 
public DateTime getOutDate() { 
    if (scenario == Scenario.OUT) { 
     return date; 
    } 
    return null; 
} 

或者,如果你正在使用Hibernate就可以使用专有的注解@Formula

@Formula("case when SCENARIO = 2 then DATE else NULL end") 
@Convert("DateTimeConverter") 
private DateTime inDate; 

@Formula("case when SCENARIO = 1 then DATE else NULL end") 
@Convert("DateTimeConverter") 
private DateTime outDate; 

我更喜欢第一个选项,因为:

  • 更容易与单元测试测试
  • 它更容易使用单位的实体测试
  • 它不需要专有扩展
  • 一般可能有一些问题与SQL的便携性,虽然在这个问题case when是SQL 92兼容,因此在这里不适用

我能唯一的问题是是,在最简单的方法是我们通过暴露于实体(scenariodate属性)的客户内部放弃封装。但是你总是可以隐藏这些属性,访问者protected,JPA仍然会处理该属性。

+0

没有计算属性,但JPA回调有助于计算实体加载后的属性。 –

1

要计算JPA实体内的属性,可以使用JPA回调。

看到这个Hibernate JPA Callbacks文档。 (注意:JPA回调不是特定于休眠,它是最新JPA 2.1 specification的一部分)。 而且这个OpenJpa JPA Calbacks之一。

继实体生命周期类别有事件可以由实体管理器进行拦截调用方法:

因此,让我们说你要计算complexLabel标签从两个坚持实体领域中的实体LABEL1LABEL2题为myEntity所

@Entity 
public class MyEntity { 

    private String label1; 

    private String label2; 

    @Transient 
    private String complexLabel; 

    @PostLoad 
    @PostUpdate // See EDIT 
    // ... 
    public void computeComplexLabel(){ 
     complexLabel = label1 + "::" + label2; 
    } 
} 

由于@Dawid写道,你必须标注complexLabel@瞬变为了让它们被持久化忽略。如果你不这样做,持久化失败,因为在MyEntity对应的表中没有这样的列。

随着@PostLoad注释,computeComplexLabel()方法是通过实体管理器只是myEntity所从持久性的任何实例的加载后调用。 因此,@PostLoad带注释的方法最适合放置您的后期加载实体属性增强代码。

娄是从JPA 2.1规范关于负荷后的提取物:

一个实体的负荷后方法一直 实体加载到从数据库或 当前的持久性的上下文之后调用刷新操作已应用于它之后。 PostLoad 方法在返回或访问查询结果之前调用,或者在遍历关联之前调用 。

编辑

正如指出的@Dawid,你也可以使用@PostUpdate的情况下,要计算只是实体更新后,这个短暂的领域,并在需要时使用其他的回调。

+0

这是另一种选择。但是,这种方法的问题是,当您更改实体时,以这种方式计算的属性不会更新。您还需要使用'@ PostUpdate'注释。坦率地说,使用可轻松计算的JPA生命周期方法会导致不必要的复杂性并使单元测试变得更加困难。另外,你需要非常小心。对于处于分离状态的实体生命周期方法(特别是'@ PostUpdate')将不起作用,给你留下陈旧的数据。 –

+0

我同意你@Dawid的PostUpdate(因为你经常想在实体更新后再次计算这个计算的属性)。但是,使用JPA回调会优化此计算,因为只有在加载(@PostLoad)或更新(@PostUpdate)后才会执行此计算,但每次获取该值时都不会执行此操作,请按照您的示例调用getter。然后,我使用getter来保持简单,所以它们不计算任何东西,只是返回字段值。关于测试,我用集成或组件测试来说明这个问题,它使用真实数据库或内存数据库的持久性单元进行测试。 –

+0

在计算需要大量资源的情况下,我同意@Rémi。然后我们可以考虑使用JPA生命周期方法。然而,在大多数情况下,特别是在问题中描述的一种情况下,恕我直言表现的收益并不能证明引入的复杂性(如果我说得对,只有1条表述)。一些团队成员可能不知道或从未使用过JPA生命周期方法。编写简单单元测试代替集成测试和复杂设置的可能性也是很诱人的。 –

相关问题