能否通过扩展POJO来构建JPA实体?

61

假设我有以下的POJO:

public class MyThing {
 private int myNumber;
 private String myData;
//assume getter/setter methods
}

现在是否可以将此POJO扩展为JPA实体?

@Entity
@Table(name = "my_thing")
public class MyThingEntity extends MyThing implements Serializable {
 @Column(name = "my_number")
 //?????????
 @Column(name = "my_data")
 //????????
}

我想把POJO与JPA实体分开。POJO在另一个项目中,并经常在没有持久层的情况下使用,我的项目希望将其保存到数据库中,而不需要从POJO到实体再进行映射。

我知道JPA实体是POJO,但是为了使用它,我必须包含一个实现javax.persistence的库,而其他使用相同基础对象的项目则不需要持久层。

这可行吗?这是个好主意吗?

2个回答

80

JPA规范规定:

实体可以扩展非实体类和实体类,非实体类也可以扩展实体类。

@javax.persistence.MappedSuperclass注解允许您定义此类映射关系。

@MappedSuperclass
public class MyThing implements Serializable {
    private int myNumber;
    private String myData;

    // getter's and setter's
}

而且

@Entity
@Table(name="MY_THING")
public class MyThingEntity extends MyThing {


}

根据JPA规范所述

MappedSuperclass注解指定了一个类,其映射信息应用于继承它的实体

而且

使用MappedSuperclass注解标记的类可以像实体一样进行映射,只是映射将仅应用于其子类,因为对于映射的超类本身不存在表。

如果需要覆盖MyThing定义的某些属性,请使用@AttributeOverride(当您想要覆盖单个属性时)或@AttributeOverrides(当您想要覆盖多个属性时)

@Entity
@Table(name="MY_THING")
@AttributeOverride(name="myData", column=@Column(name="MY_DATA"))
public class MyThingEntity extends MyThing {


}

并且

@Entity
@Table(name="MY_OTHER_THING")
@AttributeOverrides({
    @AttributeOverride(name="myData1", column=@Column(name="MY_DATA_1")),
    @AttributeOverride(name="myData2", column=@Column(name="MY_DATA_2"))
})
public class MyOtherThingEntity extends MyThing {

}
如果您不想更改基类,可以使用XML将其定义为@MappedSuperClass。请注意:默认情况下,持久性提供程序将在META-INF目录中查找名为orm.xml的文件。
<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
    <mapped-superclass class="MyThing">

    </mapped-superclass>
</entity-mappings>

只需要这样。如果你想要覆盖一个属性,请像上面所示使用 @AttributeOverride。


4
我猜测这个想法不是要改变MyThing类。 - Maxime ARNSTAMM
2
Maxime是正确的,我不想触碰基本的POJO。它可能仍然有效,@MappedSuperclass MyThingMapper extends MyThing .... MyThingEntity extends MyThingWrapper - Freiheit
1
如果您想将myNumber作为MyThingEntity的主键,该怎么办? - Manolo Santos
1
@Manolo Santos 只需在其上方放置 Id 注释即可。但是,不要忘记:每个类层次结构中应定义一个且仅一个主键。 - Arthur Ronald
尝试后的一些注意事项:1)“META-INF”位于“src/main/resources/META-INF”中。2)如果您对属性名称就是列名感到满意,那么不需要使用“@AttributeOverride”。 - Lucas
显示剩余10条评论

6
可以这样做:
  • 您可以使用XML进行映射 - 创建一个符合ORM模式orm.xml,并映射您的POJO的列,甚至无需扩展它。在一个环境中,它将启用JPA,在另一个环境中则是POJO
  • 只覆盖getter方法并对其进行注释 - (我不确定这是否有效)

话虽如此,我认为这并不必要。只需对您的POJO进行注释,并将编译时依赖项添加到您的项目中。然后每个项目都将决定是否将它们用作JPA实体。


请注意,您必须找到一种方法来通知 POJO 已更改,以便您可以更改映射文件。 - Aaron Digulla
暂且假设运行拥有POJO的项目的团队绝不会允许我提交带有JPA注释和javax.persistence导入的补丁。是否存在“虚拟”的javax.persistence库,以便导入工作,但如果不需要持久性,则无需拖动EclipseLink JAR文件? - Freiheit
1
仅有注释并不会导致运行时问题,即使包含它们的jar文件不存在。在编译时仍然需要它。我不确定其他地方是否有这个,但Maven在存储库中有一个javax.persistence-persistence-api-1.0.jar(http://mvnrepository.com/artifact/javax.persistence/persistence-api/1.0)。 - ColinD
1
@ColinD - 这实际上非常有趣。我们不能在POJO中“污染”注释的原因是它被其他几个项目使用,并且必须拖动Maven或Eclipselink JAR来提供javax.persistence类是不可接受的。所以根据你的说法,我们可以在这些JAR存在的情况下构建,然后在不需要JPA的项目中分发而不使用它们。 - Freiheit
1
只要使用注释(枚举也可以,只要它们仅在注释内部使用),JPA 在运行时不需要存在。 - ColinD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接