有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

javajpa继承问题

使用JPA1(hibernate core版本3.3.0.SP1和hibernate entitymanager版本3.4.0.GA): 我有一些类似于下面定义的实体,其中ChildOne和ChildTwo扩展自父实体

@Entity
@Table(name = "TABLE_FATHER")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(discriminatorType = DiscriminatorType.INTEGER, name = Father.C_ID_CTG)
public class Father {

@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "sq")
@Column(name = "ID_PK", nullable = false)
@BusinessId
private Long id;
...
} 

@Entity
@Table(name = "TABLE_CHILD_ONE")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorValue(Categories.ID_CTG_ONE)
public class ChildOne extends Father {
    ...
}

@Entity
@Table(name = "TABLE_CHILD_TWO")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorValue(Categories.ID_CTG_TWO)
public class ChildTwo extends Element {
    ...
} 

假设一个实体有一个父元素,另一个实体有一个父元素集合。在这两种情况下,都应该转到子实体

@Entity
@Table(name = "TABLE_ONE")
public class OneTable {

@JoinColumn(name = "ID_PK", referencedColumnName = "ID_PK", nullable = false)
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private Father element; 
    ...
} 

@Entity
@Table(name = "TABLE_ANOTHER")
public class Another  {

@Fetch(FetchMode.JOIN)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "id", fetch = FetchType.LAZY)
private Collection<Father> elementCollection;

    ...
} 

我希望总是获得子元素,但当我获得元素时getElement()返回父元素 另一方面,当我得到集合getElementCollection()时,子元素就来了

显然,@JoinColumn是这种行为的原因,它与父表进行连接,而忘记了子元素。 集合正在按预期工作

如何通过getElement()调用获取children元素?有什么想法或想法吗? 提前谢谢


共 (1) 个答案

  1. # 1 楼答案

    这个问题不是由@JoinColumn引起的。 原因是延迟加载。 我设法用更简单的例子指出了你的问题。 请原谅我把传统从父亲变成了父母

    在下面的示例中,未初始化的元素是jpa.inheritance.issue.Parent_$$_javassist_1类型。它是一个Hibernate代理——动态创建的父类的子类。 您可以通过调用Hibernate专有API getHibernateLazyInitializer().getImplementation()来“取消固定”它

    elementCollection的集合也已初始化。集合的类型为org.hibernate.collection.PersistentBag,在第一次访问时使用正确的数据初始化。 集合一次全部初始化。 请查看与您的Hibernate(3.3.0.SP1/3.4.0.GA)完全相同的版本成功通过绿色测试的测试

        @Test
        public void test() {
            Child c = new Child();
            em.persist(c);
    
            Another a = new Another();
            a.setElement(c);
            Collection<Parent> col = new ArrayList<Parent>();
            col.add(c);
            a.setElementCollection(col);
            em.persist(a);
            c.setAnother(a);
    
            long idx = a.getId();
            tx.commit();
    
            // I'm cleaning the cache to be sure that call to a.getElement() will return proxy.
            em.clear();
            tx = em.getTransaction();
            tx.begin();
    
            a = em.find(Another.class, idx);
            Assert.assertNotNull(a);
            Parent p = a.getElement();
            // At this point p is a type of jpa.inheritance.issue.Parent_$$_javassist_1
    
            Assert.assertTrue(p instanceof Parent);
            Assert.assertFalse(p instanceof Child);
    
            // At this point a.elements is a not initialized (empty) collection of type org.hibernate.collection.PersistentBag
            // When we access this collection for the first time, records are read from the database 
            Assert.assertEquals(1, a.getElementCollection().size());
    
            if (p instanceof HibernateProxy) {
                p =
                        (Parent) ((HibernateProxy) p).getHibernateLazyInitializer()
                                .getImplementation();
            }
    
            // At this point p is a type of jpa.inheritance.issue.Child
            Assert.assertTrue(p instanceof Child);
        }
    
        @Entity
        public class Another {
    
            @JoinColumn(name = "element_id", referencedColumnName = "id", nullable = false)
            @ManyToOne(fetch=FetchType.LAZY)
            private Parent element; 
            public Parent getElement() {
                return element;
            }
    
            public void setElement(Parent element) {
                this.element = element;
            }
    
            @OneToMany(cascade = CascadeType.ALL, mappedBy = "another", fetch = FetchType.LAZY)
            public Collection<Parent> elements;
    
            public Collection<Parent> getElementCollection() {
                return elements;
            }
    
            public void setElementCollection(Collection<Parent> elementCollection) {
                this.elements = elementCollection;
            }
    
            // @Id ...
        }
    
        @Entity
        @Inheritance(strategy = InheritanceType.JOINED)
        public class Parent {
            @ManyToOne
            private Another another;
    
            public Another getAnother() {
                return another;
            }
    
            public void setAnother(Another another) {
                this.another = another;
            }
    
            // @Id ...
        }
    
        @Entity
        public class Child extends Parent {         
        }
    

    您不需要@DiscriminatorColumn@DiscriminatorValue,因为这些注释是InheritanceType.SINGLE_TABLE确定类型的唯一手段。 有了InheritanceType.JOINED,Hibernate可以通过检查(父表和子表)中是否有具有相同Id的记录来确定多态类型。 您可以打开hibernate日志来查看用于确定类型的查询的外观。它的工作原理如下:

    select
        another0_.id as id0_1_,
        another0_.element_id as element2_0_1_,
        parent1_.id as id1_0_,
        parent1_1_.name as name2_0_,
        case
            when parent1_1_.id is not null then 1
            when parent1_.id is not null then 0
            else -1
        end as clazz_0_
    from
        Another another0_
    inner join
        Parent parent1_
            on another0_.element_id=parent1_.id
    left outer join
        Child parent1_1_
            on parent1_.id=parent1_1_.id
    where
        another0_.id=?