【问题标题】:Is it possible to build a JPA entity by extending a POJO?是否可以通过扩展 POJO 来构建 JPA 实体?
【发布时间】:2011-01-31 18:14:46
【问题描述】:

假设我有以下 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 的库,而使用相同基础对象的其他项目对持久层没有用处。

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

【问题讨论】:

    标签: java jpa


    【解决方案1】:

    有可能:

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

    也就是说,我认为没有必要这样做。只需注释您的 POJO,并将编译时依赖项添加到您的项目中。然后每个项目将决定是否将它们用作 JPA 实体。

    【讨论】:

    • 请注意,您必须找到一种方法来通知 POJO 何时更改,以便您可以更改映射文件。
    • 现在让我们假设运行具有 POJO 的项目的团队在任何情况下都不允许我提交带有 JPA 注释和 javax.persistence 导入的补丁。是否存在诸如“虚拟” javax.persistence 库之类的东西,以便导入工作,但如果不需要持久性,则无需拖动 EclipseLink JAR?
    • 即使包含它们的 jar 不存在,单独的注释也不会导致运行时问题。在编译时仍然需要它。我不确定还有什么可用的,但 Maven 在存储库中有一个 javax.persistence-persistence-api-1.0.jar (mvnrepository.com/artifact/javax.persistence/persistence-api/…)。
    • @ColinD - 这实际上非常有趣。我们不能用注释“污染” POJO 的原因是它被其他几个项目使用并且必须在 Maven 或 Eclipselink JAR 周围拖动以提供 javax.persistence 类是不可接受的。因此,根据您的说法,我们可以使用现有的 JAR 进行构建,然后在不需要 JPA 的项目中分发它们。
    • 是的,只要只使用注解(枚举也可以,只要它们只在注解中使用),JPA 不需要在运行时出现。跨度>
    【解决方案2】:

    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,如上所示

    【讨论】:

    • 我怀疑这个想法不是为了改变 MyThing 类
    • Maxime 是正确的,我根本不想触及基础 POJO。它可能仍然有效,@MappedSuperclass MyThingMapper extends MyThing .... MyThingEntity extends MyThingWrapper
    • @Freiheit 添加到原始答案
    • 如果你想让myNumber成为MyThingEntity的主键怎么办?
    • @Manolo Santos 只需在其上方放置 Id 注释即可。但是,不要忘记:您应该为每个类层次结构定义一个,并且只有一个主键。
    猜你喜欢
    • 2012-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多