【问题标题】:Hibernate generated select statement has two ids, entity id value populated with a null on loadHibernate 生成的 select 语句有两个 id,实体 id 值在加载时填充为空
【发布时间】:2013-12-31 01:24:10
【问题描述】:

我们有 Hibernate 拦截器(扩展 EmptyInterceptor),它根据传入的 entityName 在实例化时加载 Spring 类:

@Override
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
    Object bean = null;
    String className = entityName.substring(entityName.lastIndexOf(".") + 1);
    StringBuffer entity = new StringBuffer(className.substring(0, 1).toLowerCase());
    entity.append(className.substring(1));
    String beanName = entity.toString();
            // Place any modified bean names here
    if ("policyType".equalsIgnoreCase(entity.toString())) {
        beanName = "policyTypeEntity";
    }

    if (this.applicationContext.containsBean(beanName)) {
        bean = this.applicationContext.getBean(beanName);
    }
    return bean;
}

基于此设置,当运行 createCriteria 查询时,

this.policyInfo = (PolicyInfo) session.createCriteria(PolicyInfo.class).createAlias("quote", "q").add(Restrictions.eq("q.id", quoteId)).uniqueResult();

Hibernate 正在生成如下所有 SQL(删节)(这只是急切初始化的子查询之一):

 /* load one-to-many com.ipacc.onelink.model.entitybeans.PolicyInfo.persons */ select
    persons0_.POLICY_INFO_ID as POLICY_I5_35_1_,
    persons0_.ID as ID1_27_1_,
    persons0_.ID as ID1_27_0_,
    persons0_.WORK_ADDRESS_ID as WORK_ADD2_27_0_,
    persons0_.HOME_ADDRESS_ID as HOME_ADD3_27_0_,
    persons0_.MAIL_ADDRESS_ID as MAIL_ADD4_27_0_,
    persons0_.POLICY_INFO_ID as POLICY_I5_27_0_,
    persons0_.HOMEOWNER_VERIFIED as HOMEOWN26_27_0_ 
from
    COMBO21_OWNER.PERSON_INFO persons0_ 
where
    persons0_.POLICY_INFO_ID=?

如果您注意到,ID 列重复了两次,导致实际的类属性设置为 null。

PersonInfo 实体的开头如下所示: 包 com.ipacc.onelink.model.entitybeans;

import javax.persistence.Transient;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@SuppressWarnings("serial")
@Component
@Scope("prototype")
public class PersonInfo extends DomainObject implements Comparable<PersonInfo> {
private Address workAddress;
private Address homeAddress;
private Address mailAddress;
private PolicyInfo policyInfo;
private String firstName;
private String lastName;
private String middleName;
private String titlePrefix;
private String priorLastName;
private String ssn;
private Date birthDate;
private String ethnicGroup;
private String language;
and so on...

这继承了如下所示的 DomainObject: 包 com.ipacc.onelink.model;

import java.io.Serializable;

@SuppressWarnings("serial")
public class DomainObject implements Serializable {
protected Integer id;

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

public Integer getId() {
    return id;
}
}

添加删减的映射文件:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="com.ipacc.onelink.model.entitybeans.PersonInfo" table="PERSON_INFO" schema="COMBO21_OWNER" dynamic-update="true" select-before-update="true">
    <id name="id" type="integer">
        <column name="ID" precision="10" scale="0" />
        <generator class="sequence">
            <param name="sequence">PERSON_INFO_SEQ</param>
        </generator>
    </id>
    <many-to-one name="workAddress" class="com.ipacc.onelink.model.entitybeans.Address" fetch="select"
        cascade="all">
        <column name="WORK_ADDRESS_ID" precision="10" scale="0" />
    </many-to-one>

关于为什么会发生这种情况的任何想法?

谢谢

更新: 我展平了类以向下推 id 列并删除了上面提到的 DomainObject 但仍然没有取得任何进展。所以我们可以排除 Hibernate 继承映射策略的问题(因为我不再使用祖先类)。 我也在 Hibernate 4.2.7.SP1 上试过这个,所以我可以确认这也是以前版本中的一个问题。我不认为这是 Hibernate 问题,而是使用实例化拦截器时 Spring 和 Hibernate 之间的握手问题。

这是我得到的重复 ID: 休眠: /* 加载一对多的 com.ipacc.onelink.model.entitybeans.PolicyInfo.installments */ select installmen0_.POLICY_INFO_ID 为 POLICY_I2_35_1_, installmen0_.ID 为 ID1_18_1_, installmen0_.ID 为 ID1_18_0_, installmen0_.POLICY_INFO_ID 为 POLICY_I2_18_0_, 休眠: /* 加载一对多的 com.ipacc.onelink.model.entitybeans.PolicyInfo.policyQuestionAnswers */ select policyques0_.POLICY_INFO_ID 为 POLICY_I2_35_2_, policyques0_.ID 为 ID1_37_2_, policyques0_.ID 为 ID1_37_1_,

有没有人用Hibernate EmptyInterceptor的instantiate方法实例化Spring bean并且成功了?

【问题讨论】:

  • 在初始化 Hibernate Session 和 Spring 上下文创建期间是否有任何线程问题=。此外,请提供您的 Person 实体。
  • 在 Hibernate Session 或 Spring Context 创建期间看不到任何线程异常。我已经更新了原始版本以包含实体信息的删减版本。
  • 你的实体的所有映射注解在哪里?
  • JB,我已经从 hbm.xml 文件中添加了删减的映射信息。
  • 您是否使用不同的休眠会话并行执行查询。在这种情况下,可能是一些休眠缓存问题。在一个线程中,人员实体已经附加到会话,而在另一个线程中则没有。这种情况下不能抛出异常。

标签: java sql spring hibernate


【解决方案1】:

我认为这是您的 PersonInfo 类中的映射问题。 您有 3 个不同的地址关联。在我看来,这是一个数据库设计问题。在这种情况下,外键关联应该由地址类或实体管理。检查此关联是如何实现的。

此外,PersonInfo 与它自己的关联。递归依赖。

public class PersonInfo extends DomainObject implements Comparable<PersonInfo> {
   private Address workAddress;
   private Address homeAddress;
   private Address mailAddress;
   private PolicyInfo policyInfo;

所以检查映射是否有问题,如果没有,检查 Spring 是否能够解决 那种带有拦截器机制的递归依赖。我不知道,但这可能是个问题。

尝试简化您的 PersonInfo 映射并检查它是否比 Spring 和 Interceptor 机制以正确的方式工作。

【讨论】:

  • 这不仅是 PersonInfo 的问题,而且是在加载时从数据库加载的所有实体的问题。所以我们可以排除这是映射问题。
【解决方案2】:

我想我有一个可能的答案。您没有为您的 DomainObject 和 PersonInfo 关联。

检查继承策略及其要求。似乎您的 PersonInfo 类 在默认继承策略的情况下需要一个额外的 Id 属性。

存在以下策略

  • 每个类层次结构的表
  • 每类表
  • 每个具体类的表

我认为您的映射没有提供任何继承策略定义。 此外,您可以使用基于注释的映射来进行这种继承。 但是您使用 xml 映射,在我看来您没有定义该关联。

此外,我认为您尝试使用对 PersonInfo 引用的递归依赖来解决此继承依赖。但这只是一个假设。

所以这应该是为什么有两个 id 的原因。 DomainObject 表的一个 id 和 PersonInfo 表的一个 id。检查您是否有一个对 PersonInfo 有外键约束的 DomainObject 或检查您的继承策略。

【讨论】:

  • 没有 DomainObject 表。我使用隐式多态策略为每个具体类使用表。所以这应该没问题,对吗?
  • 在每个具体类的表的情况下,您需要为 domainobject 和 PersonInfo 类指定映射。另外,您需要子类映射中的 id 属性以及任何其他派生属性。这是一个很好的教程,它通过示例描述了不同的策略:viralpatel.net/blogs/…
  • 感谢您的快速回复。由于我在实例化时使用 Spring 注入 bean,这真的很重要吗?创建 DomainObject 类的目的是将 id 列集中到所有实体对象中,并将每个实体声明为可序列化。不打算将 DomainObject 存储为表。
  • 我不认为这是一个弹簧问题。尝试通过将 DomainObject 类添加到 hbm 来调整您的映射。比休眠创建额外的表DomainObject,这在表p的情况下是必要的。具体类。请告诉我生成的休眠查询是否还包含 person_ids。应该。一个映射到 DomainObject 表,一个映射到 PersonInfo
  • 每个实体对象(从 DomainObject 类派生)都有自己的序列作为生成器类。所以如果我要创建一个新的 DomainObject.hbm.xml,生成器类会是什么?另外,当没有代表这个的物理表时,它会引用哪个表?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-14
  • 2011-09-09
  • 1970-01-01
  • 2011-04-13
  • 1970-01-01
  • 2018-01-14
相关资源
最近更新 更多