【问题标题】:JPA: difference between setting @Id on fied and on getterJPA:在字段和 getter 上设置 @Id 之间的区别
【发布时间】:2016-09-13 01:40:56
【问题描述】:

我使用 EclipseLink 得到了非常奇怪的结果。请考虑以下代码:

此代码有效:

@Entity
@Table(name = "someTable")
public class SomeClass{
    @Id// PAY ATTENTION TO THIS LINE
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Column (name = "somecol")// PAY ATTENTION TO THIS LINE
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

此代码也有效:

@Entity
@Table(name = "someTable")
public class SomeClass{
    @Id// PAY ATTENTION TO THIS LINE
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    //@Column (name = "somecol")// PAY ATTENTION TO THIS LINE
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

此代码也有效:

@Entity
@Table(name = "someTable")
public class SomeClass{

    private String id;

    @Id// PAY ATTENTION TO THIS LINE
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    //@Column (name = "somecol")// PAY ATTENTION TO THIS LINE
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

此代码不起作用:

@Entity
@Table(name = "someTable")
public class SomeClass{

    private String id;

    @Id // PAY ATTENTION TO THIS LINE
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Column (name = "somecol")// PAY ATTENTION TO THIS LINE
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

我得到以下异常:

Exception Description: Entity class [class SomeClass] has no primary key specified. It should define either an @Id, @EmbeddedId or an @IdClass. If you have defined PK using any of these annotations then make sure that you do not have mixed access-type (both fields and properties annotated) in your entity class hierarchy.
    at org.eclipse.persistence.exceptions.ValidationException.noPrimaryKeyAnnotationsFound(ValidationException.java:1425)
    at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.validatePrimaryKey(EntityAccessor.java:1542)
    at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.processMappingAccessors(EntityAccessor.java:1249)
    at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.process(EntityAccessor.java:699)
    at org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processStage2(MetadataProject.java:1808)
    at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.processORMMetadata(MetadataProcessor.java:573)
    at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:607)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1948)
    at org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.callPredeploy(JPAInitializer.java:100)
    at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:104)
    at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:188)
    at org.eclipse.gemini.jpa.ProviderWrapper.createEntityManagerFactory(ProviderWrapper.java:128)
    at org.eclipse.gemini.jpa.proxy.EMFServiceProxyHandler.createEMF(EMFServiceProxyHandler.java:151)
    at org.eclipse.gemini.jpa.proxy.EMFServiceProxyHandler.syncGetEMFAndSetIfAbsent(EMFServiceProxyHandler.java:127)
    at org.eclipse.gemini.jpa.proxy.EMFServiceProxyHandler.invoke(EMFServiceProxyHandler.java:73)
    at com.sun.proxy.$Proxy8.createEntityManager(Unknown Source)

为什么最后一个代码不起作用?怎么解释?

【问题讨论】:

    标签: java jpa eclipselink


    【解决方案1】:

    这是因为如果您想使用混合模式,则必须在实体和字段级别指定 @Access 之类的内容。有两个值AccessType.PROPERTYAccesType.FIELD

    默认访问类型由您放置标识符注释的位置 (@Id) 定义。如果你把它放在字段上 - 它将是AccessType.FIELD,如果你把它放在吸气剂上 - 它将是AccessType.PROPERTY - 已编辑,不是由 JPA 定义的。

    如果您想注释的不是字段而是属性(字段上仍然有@Id),您必须定义一个getter 并将其注释为AccessType.PROPERTY。 (反之亦然 @Id 在 getter 上)。

    【讨论】:

    • 我很困惑:如果放置@Id的地方决定AccessType,为什么会抱怨“没有指定主键”?根据您的回答,最后一个示例将默认为 AccessType.PROPERTY 并且 @Id 注释放在正确的位置不是吗?
    • 只是进一步搜索给我这个答案:stackoverflow.com/a/13874900/395202 你所说的与 答案 相同,但事实证明,在 评论 答案部分,建议的这种行为(@Id 决定 AccessType)不是 JPA 标准。 (而且它也没有解释 OP 面临的行为)
    • 我刚刚阅读了您发布的内容。老实说,我记得关于 AccessType 的那一点——仅仅是因为我在 JPA 培训中有一个关于它的练习(但我使用 Hibernate 作为提供者)。我现在理解的是 EclipseLink 对待它的方式不同。尽管如此,你是对的。我的回答没有回答实际问题,这就是为什么没有 PK 异常:)。但肯定有助于避免这些症状。
    • 我猜 JPA 的标准坚持访问类型需要在整个类中都是标准的(即使在我相信的整个层次结构中)。由供应商决定如何处理不一致的情况。很好的答案,因为它为其他人(包括我)提供了正确的方向,以了解更多问题:)
    猜你喜欢
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    • 2011-03-25
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    相关资源
    最近更新 更多