【问题标题】:Hibernate Criteria joining unrelated children?加入无关儿童的休眠标准?
【发布时间】:2014-09-05 18:50:37
【问题描述】:

我有三个实体,一个父母有两个孩子,但我在这里只列出了两个实体。

@Entity
@Table(name = "person")
public class Person{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, nullable = false) 
    private Long id;

    @Column(name = "name")
    private String name;

    @OneToMany(fetch=FetchType.EAGER)
    private Set<Phone> phones = new HashSet<Phone>();


    @OneToMany(fetch=FetchType.EAGER)
    @JoinColumn(name="person_id", referencedColumnName="id")        
    private List<Book> books = new ArrayList<Book>();

}


@Entity
@Table(name = "book")   
public class Book{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, nullable = false) 
    private Long id;

    @Column(name="person_id")
    private Long personId;

}

当我按照 Hibernate 标准运行并从 SQL 生成的日志中注意到时,它正在将两个孩子 - 电话和书籍连接在一起。我和这两个孩子没有任何关系。为什么从 Hibernate 条件生成的 SQL 查询会尝试加入不相关的两个孩子?我希望加入发生在父母和孩子之间,而不是孩子之间。

        Criteria criteria = session.createCriteria(Person.class)
                .add(Restrictions.in("id", ids))
                .setFetchMode("phones", FetchMode.JOIN).setFetchMode("books", FetchMode.JOIN)
                .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);               
        result = criteria.list();

【问题讨论】:

    标签: hibernate hibernate-mapping hibernate-criteria


    【解决方案1】:

    如果你想使用条件,那么你需要为每个关系发布两个条件:

    result = session.createCriteria(Person.class)
                    .add(Restrictions.in("id", ids))
                    .setFetchMode("phones", FetchMode.JOIN)
                    .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
    
       and
    
    result =         session.createCriteria(Person.class)
                    .add(Restrictions.in("id", ids))
                    .setFetchMode("books", FetchMode.JOIN)
                    .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
    

    否则,您可以使用 hql 代替条件并具有:

     String hql=  "select new list(person.phones, person.books) from Person person";
    session.createQuery(hql).list();
    

    编辑:

    String hqlQuery = "select p from Person p left outer join p.phones as ph left outer join p.books as b";
    

    【讨论】:

    • 感谢您的回复。我希望得到一个 Person 对象的集合,其中包括它的所有属性——id、name、电话和书籍。那么,它不能用一个标准来完成吗?在我的真实模型中,我在 Person 类中有大量属性。如果我使用 hql,有没有办法获取包含其所有属性的 Person 对象集合?
    • 是的,您可以通过 hql 中的简单左外连接来做到这一点。查看我的编辑。
    • 左外连接有效,但我有两个问题。首先,我需要根据 Person Id 删除重复项。其次,我看到对于每个人的 id,它会创建两个查询——一个用于电话,一个用于书籍。有什么方法可以应用 FetchMode.JOIN 使其成为一个查询?如果我在数据库中有 20,000 条人员记录,这将创建 40,000 条选择语句。
    • 更正我之前的评论。第一个问题不存在。我错了。正如我之前提到的,如果我有 20,000 个人员记录,当我运行“从 p.id in (:ids) 中的 Person person 中选择新列表(person.phones, person.books)”时,它会创建 40,000 个查询。对于每个人的 ID,我看到两次“116 Query select”语句。这对性能有何影响?顺便说一句,我正在使用您的 hqlQuery,因为 Criteria 方法没有返回我想要的。即使 Criteria 方法有效,它也会将整个大对象两次加载到内存中。
    • 你试过最后一个使用左外连接的 hqlQuery 吗,它在单个查询中获取所有人员对象
    猜你喜欢
    • 1970-01-01
    • 2011-10-23
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    相关资源
    最近更新 更多