【问题标题】:JPA/Hibernate Query failure related to entity variable name与实体变量名称相关的 JPA/Hibernate 查询失败
【发布时间】:2012-03-27 06:33:19
【问题描述】:

我是 JPA 的新手,在过去的 4 天里我一直在试图弄清楚为什么 *&^!@ 我的查询一直在爆炸。经过一番折腾,问题似乎与我正在使用的变量的名称有关。请参阅下面的我的实体和测试类。我为 enormopost 道歉,但我已尝试尽可能简化它。

@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
@Column(length = 50)
private String name;
@ManyToOne
private MyEntity myEntity;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "myEnt", fetch = FetchType.EAGER)
@MapKey(name = "typeName")
private Map<String, ContainedEntity> ecConfigs;

public MyEntity() {
}

public MyEntity(String name, MyEntity myEntity) {
    this.name = name;
    this.myEntity = myEntity;
}

public MyEntity(String name) {
    this.name = name;
}

public String getName() {
    return name;
}

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

public long getId() {
    return id;
}

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

public Map<String, ContainedEntity> getEcConfigs() {
    return ecConfigs;
}

public void setEcConfigs(Map<String, ContainedEntity> ecConfigs) {
    this.ecConfigs = ecConfigs;
}

public MyEntity getMyEntity() {
    return myEntity;
}

public void setMyEntity(MyEntity myEntity) {
    this.myEntity = myEntity;
}

public String toString() {
    return name + " -- " + myEntity;
}
}
@IdClass(ContainedEntityPK.class)
@Entity
public class ContainedEntity {

@Id
private String typeName;
@Id
private MyEntity myEnt;
@Column(length = 255)
private String ceName;

public ContainedEntity() {
}

public ContainedEntity(String typeName, String ceName) {
    super();
    this.typeName = typeName;
    this.ceName = ceName;
}

public String getTypeName() {
    return typeName;
}

public void setTypeName(String typeName) {
    this.typeName = typeName;
}

public MyEntity getMyEnt() {
    return myEnt;
}

public void setMyEnt(MyEntity myEnt) {
    this.myEnt = myEnt;
}

public String getCeName() {
    return ceName;
}

public void setCeName(String ceName) {
    this.ceName = ceName;
}

}
public class ContainedEntityPK implements Serializable{
private static final long serialVersionUID = -1714218588564578557L;
@Column(length = 255)
private String typeName;
@ManyToOne
private MyEntity myEnt;

public ContainedEntityPK() {
}

public ContainedEntityPK(String typeName, MyEntity myEnt) {
    super();
    this.typeName = typeName;
    this.myEnt = myEnt;
}

public String getTypeName() {
    return typeName;
}

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

public MyEntity getMyEnt() {
    return myEnt;
}

public void setMyEnt(MyEntity myEnt) {
    this.myEnt = myEnt;
}

public int hashCode() {
    return (int) (typeName.hashCode() + myEnt.hashCode());
}

public boolean equals(Object obj) {
    if (obj == null)
        return false;
    if (obj == this)
        return true;
    if (!(obj instanceof ContainedEntityPK))
        return false;
    ContainedEntityPK pk = (ContainedEntityPK) obj;
    return pk.getMyEnt().equals(myEnt) && pk.typeName.equals(typeName);
}
}
public class Tester {
static EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPersistenceUnit");

/**
 * @param args
 */
public static void main(String[] args) {
    addEntities();
    findEntity("aEntity");
    findEntity("bEntity");
}

public static void addEntities() {
    EntityManager em = emf.createEntityManager();

    MyEntity aEntity = new MyEntity("aEntity");
    MyEntity bEntity = new MyEntity("bEntity", aEntity);

    em.getTransaction().begin();
    em.persist(aEntity);
    em.persist(bEntity);
    em.getTransaction().commit();
    em.close();
}

public static void findEntity(String name) {
    EntityManager em = emf.createEntityManager();

    TypedQuery<MyEntity> q = em.createQuery("SELECT M FROM MyEntity M WHERE M.name=:name", MyEntity.class);
    q.setParameter("name", name);
    System.out.println(q.getSingleResult());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="testPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>test.nocommit.MyEntity</class>
<class>test.nocommit.ContainedEntity</class>
<properties>
  <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
  <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@server:1521:instance"/>
  <property name="javax.persistence.jdbc.user" value="user"/>
  <property name="javax.persistence.jdbc.password" value="pass"/>
  <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
  <property name="hibernate.hbm2ddl.auto" value="create"/> 
</properties>
</persistence-unit>
</persistence>

当我运行之前的主类时,它的行为符合我的预期并得到以下输出:
aEntity -- null
bEntity -- aEntity -- null

但是,如果我将 MyEntity.ecConfigs 变量名称更改为 MyEntity.secConfigs 并将 getter/setter 更改为:

    public Map<String, ContainedEntity> getSecConfigs() {
        return secConfigs;
    }

    public void setSecConfigs(Map<String, ContainedEntity> secConfigs) {
        this.secConfigs = secConfigs;
    }

它在 findEntity("bEntity");称呼。我的输出是:
aEntity -- null
后跟异常:

Exception in thread "main" org.hibernate.AssertionFailure: null identifier
    at org.hibernate.engine.spi.EntityKey.<init>(EntityKey.java:69)
    at org.hibernate.internal.AbstractSessionImpl.generateEntityKey(AbstractSessionImpl.java:240)
    at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:722)
    at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:635)
    at org.hibernate.loader.Loader.doQuery(Loader.java:856)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:289)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:2058)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:82)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:72)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3697)
    at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:439)
    at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:420)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:204)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:251)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:148)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:954)
    at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:903)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:610)
    at org.hibernate.type.EntityType.resolve(EntityType.java:438)
    at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:150)
    at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1006)
    at org.hibernate.loader.Loader.doQuery(Loader.java:883)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:289)
    at org.hibernate.loader.Loader.doList(Loader.java:2463)
    at org.hibernate.loader.Loader.doList(Loader.java:2449)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2279)
    at org.hibernate.loader.Loader.list(Loader.java:2274)
    at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355)
    at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:196)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1115)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
    at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:280)
    at test.nocommit.Tester.findEntity(Tester.java:38)
    at test.nocommit.Tester.main(Tester.java:17)

起初我将此归咎于 Spring,但我已经剥离了 Spring 的所有内容,但仍然遇到问题。

我的休眠版本自称为 4.0.1.Final

我在这里遗漏了什么吗?有一些变量名要求吗?我踩到了一些保留字吗?我没有正确指定一些东西吗?据我所知,可能与自引用实体以及复合主键有某种关系......我目前在我的隔间里感到困惑和小声哭泣。

【问题讨论】:

  • 在 DataNucleus JPA 上运行良好(使用 ecConfigs 或 secConfigs)。我在任何地方都看不到保留字,而且如果某些东西是 RDBMS 中的保留字,那么 JPA 实现很容易引用它。请注意,您尚未在 GeneratedValue 中指定序列名称,因此需要添加它(可能只是错过了帖子但您真的拥有它?)

标签: java database oracle hibernate jpa


【解决方案1】:

JPA 的美妙之处在于它是一种规范,而不是一种实现。您的代码看起来像是针对 JPA 规范而不是休眠编写的。

我发现 EclipseLink 在它的错误消息中有很多 更好的描述,以便在你搞砸时。我会尝试使用 EclipseLink 运行您的代码,看看您是否会收到更好的错误消息。

我会一直查看您的代码,直到那时我才能发现问题所在...

【讨论】:

  • 有趣...我接受了您的建议,EcliplseLink 似乎对此有意见...但完全不同。
  • '异常描述:从 [test.nocommit.ContainedEntityPK] 派生的类型为 [test.nocommit.MyEntity] 的复合主键属性 [myEnt] 应与其父 id 字段的类型相同[test.nocommit.MyEntity]。也就是说,它应该是 [java.lang.Long] 类型。更好的错误信息。它显然对 PK 很生气,所以我将 myEnt 类型更改为 long,它在 EclipseLink 中工作。那是应该如何定义 PK 中的复杂类型吗?另外,我用这个 pk 改回休眠状态,直到我尝试持久化包含 ContainedEntity 的 MyEntity。
  • 'Caused by: java.lang.IllegalArgumentException: Can not set long field test.nocommit.ContainedEntityPK.myEnt to test.nocommit.MyEntity' 所以,Hibernate 有点喜欢这种方式,直到我使用它,然后它明确地不喜欢它......啊。旁注...看来我已与我的霸主宣布的 Hibernate 结婚,以保持与其他产品集的一致性。
【解决方案2】:

好吧,这不是一个简单的解决方案,我今天遇到了两个 Pojo(A 和 B)的相同问题,它们都有一个 java.utl.Long 字段作为@Id。 A pojo 有一个字段,它是另一个实体的集合。

我的加载过程类似这样:A -> B -> B.c

加载过程因为c而崩溃,加载c时抛出一个Missing param IN/OUT,但这隐藏在报告的异常后面。

在我的情况下,我能够解决问题,因为使用 fetchmode 'SELECT' 而不是 'SUBSELECT' 从 B 中分离 c。但我花了 8 小时搜索信息。我的休眠版本是 3.6.10-Final

【讨论】:

    猜你喜欢
    • 2019-04-14
    • 1970-01-01
    • 1970-01-01
    • 2021-03-07
    • 2016-09-12
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多