Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA继承问题_Java_Hibernate_Inheritance_Jpa - Fatal编程技术网

Java JPA继承问题

Java JPA继承问题,java,hibernate,inheritance,jpa,Java,Hibernate,Inheritance,Jpa,使用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 = Discriminator

使用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;

    ...
} 
@实体
@表(name=“Table_ONE”)
公共类一表{
@JoinColumn(name=“ID\u PK”,referencedColumnName=“ID\u PK”,nullable=false)
@ManyToOne(可选=false,fetch=FetchType.LAZY)
私人父亲因素;
...
} 
@实体
@表(name=“Table_其他”)
公开课{
@Fetch(FetchMode.JOIN)
@OneToMany(cascade=CascadeType.ALL,mappedBy=“id”,fetch=FetchType.LAZY)
私人收藏元素收藏;
...
} 
我希望总是获得子元素,但当我获得元素
getElement()
时,返回父元素 另一方面,当我得到集合
getElementCollection()
时,子元素就来了

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

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

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

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

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


只是一些关于你答案的注释。。。据我所知,规范不要求实现使用鉴别器列来实现连接继承,但是,假设是如果指定了@DiscriminatorColumn,那么将使用它。。。另一方面,尽管你的解决方案确实有效,但仍然有一些疑问。知道懒人会返回代理,为什么很多人会将代理返回给父代(jpa.heritation.issue.parent\u$$\ ujavassist\u1)和OneToMany集合子代(jpa.heritation.issue.ChildOne\u$$\ ujavassist\u1)??实际应用程序中
getElement()
调用的确切返回类型是不确定的。原因如果在一级或二级缓存中找到该对象,则该对象的类型将为
子对象。这就是为什么我在中间调用<代码> EM.CULL()和代码>来确定特定的行为。这就是为什么在父子层次结构的情况下最好是类型不可知的。如果你真的需要一个正确的类型,你可以像我建议的那样“取消固定”,或者最好将FetchType改为“渴望”(因为“取消固定”加载关系)。关于ManyTone,我将在不久的将来发布一些信息。你的评论很有趣!非常感谢您抽出时间!但这是另一件我不太确定的事情。。。我已经尝试将FetchType更改为Eager(这是我的第一个选项),但仍然有相同的行为(这意味着,使用Eager fetching的集合仍然以相同的方式返回代理元素)em.clean()?我猜你是指他们。明白了。。。我也考虑过这一点,但它不适用于我的特定情况(但我知道这可能是一个选项)是的,
em.clear()
。但这还不够。为了可靠地通过测试,我必须关闭二级缓存,清除EntityManager并重新启动事务。。。我不推荐在生产中使用。您确定必须依赖于确切的类型吗?也许是时候重新设计了?
    @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 {         
    }
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=?