1

我知道对此有很多问题,但没有一个解决方案对我有帮助。

我正在使用 PrimeFaces 构建一个惰性加载数据表。这意味着这个数据表列表是一个 LazyDataModel 列表,我必须开发一个 LazyDataModel 实现,其中我覆盖了加载方法。所有这些都可以从PrimeFaces 展示中学到,并且在大多数情况下,当数据表只使用数据库中的一个表时(这不是我的情况),它都可以正常工作。

现在,我有两个实体:

@Entity
@Table(name="UNIVERSITY")
public class University {

    @Id 
    @Column(name="ID_UNIVERSITY")   
    @GeneratedValue(strategy = GenerationType.AUTO ,generator="SQ_UNIVERSITY")  
    @SequenceGenerator(name="SQ_UNIVERSITY", sequenceName="SQ_UNIVERSITY")
    private Long idUniversity;

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

    @ManyToOne
    @JoinColumn(name="ID_DIRECTOR")
    private Director director;

    @OneToMany(fetch=FetchType.EAGER, mappedBy = "university")
    private Set<Students> students = new HashSet<Students>(0);

    ...

    public int getStudentsQty(){
        return this.students.size();
    }

    ...

我将使用该getStudentsQty()方法从我的数据表中填充一列。这是学生实体:

@Entity
@Table(name="STUDENTS")
public class Students 
{

    @Id 
    @Column(name="ID_STUDENTS") 
    @GeneratedValue(strategy = GenerationType.AUTO ,generator="SQ_STUDENTS")    
    @SequenceGenerator(name="SQ_STUDENTS", sequenceName="SQ_STUDENTS")
    private Long idStudent;

    @ManyToOne
    @JoinColumn(name="ID_UNIVERSITY")
    private University student;

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

    ...

这是我的加载实现将使用的搜索方法:

public List<University> find(int startingAt, int maxPerPage,
        final String sortField, final SortOrder sortOrder, Map<String, String> filters) {

    session = HibernateUtil.getSession();
    Criteria criteria =session.createCriteria(University.class);    

    List<String> aliases = new ArrayList<String>();

    if(maxPerPage > 0){
        criteria.setMaxResults(maxPerPage);
    }

    criteria.setFirstResult(startingAt);

    addFiltersToCriteria(filters, criteria, aliases);

    Order order = Order.desc("name");

    if(sortField != null && !sortField.isEmpty()){

        if(sortField.contains(".")){
            String first = (sortField.split("\\."))[0];
            if(!aliases.contains(first)){
                criteria.createAlias(first, first);
                aliases.add(first);
            }
        }

        if(sortOrder.equals(SortOrder.ASCENDING)){
            order = Order.asc(sortField);
        }
        else if(sortOrder.equals(SortOrder.DESCENDING)){
            order = Order.desc(sortField);
        }
    }
    criteria.addOrder(order);

    return (List<University>) criteria.list();
}

现在,我的问题。如果我使用FetchType.LAZY,一切正常,但性能很糟糕,所以我希望使用EAGER. 如果我使用EAGER结果将按预期重复并在此处解释。我尝试在实体中实现equals()hashCode()方法以使用最后一个链接中建议的 a 但它没有工作我不知道如何。我也尝试使用with但它不起作用,因为我使用它,它要求加入。UniversityLinkedHashSetDISTINCTCriteriaaddOrder

所以,我发现另一个非常有效的建议。基本上,解决方案是进行第二次Criteria查询,仅搜索原始搜索中包含 ID 的大学。像这样:

private List<University> removeDuplicates(Order order,
        List<University> universities) {

    Criteria criteria;
    List<University> distinct = null;

    if(universities.size() > 0){

        Set<Long> idlist = new HashSet<Long>();

        for(University univ: universities){
            idlist.add(univ.getIdUniversity());
        }

        criteria = session.createCriteria(University.class);
        criteria.add(Restrictions.in("id", idlist)) ;

        distinct = (List<University>) criteria.list();

        return distinct;
    }
    else{
        return universities;
    }
}   

因此,它将为我的延迟加载分页数据表带来前 100 行。在第一次Criteria搜索中,它们将针对第一页进行排序,并且在我的第二次搜索之后将出现相同的 100 行Criteria,但现在它们将是unsorted。这是第一页的正确行,但在第一页内未排序。我不能在第二个中使用“addOder”,Criteria否则它们会重复。

最奇怪的是:如果我尝试对结果进行排序,Collections.sort结果会重复!!!如何??毕竟,我怎样才能订购我的结果?

谢谢!!

编辑:学生人数只是一个例子,我需要在另一个场景中获取每个关联实体内的信息。

4

2 回答 2

1

如果我理解正确,您正在输出一个列出大学的表格,并且您想显示每所大学的学生人数。如果是这样,将 x000 个学生记录加载到内存中只是为了进行计数是疯狂的(无论您是急切地还是懒惰地这样做)。

尝试以下方法之一:

而不是加载关联的学生来获取计数,而是使用 Hibernates @Formula 功能并将派生属性添加到您的大学实体。

@Formula(value = "select count(*) from students where university_id = ?")
private int studentCount;

创建一个数据库视图,比如说 university_summary_data ,其中包括这个计数,然后在大学中创建一个映射到这个视图的实体(就像一个表一样工作):

@OneToOne
private UniversitySummaryData data;

查看 Hibernate 的 @LazyCollection(LazyCollectionOption.EXTRA) ,这将允许您在映射集合上调用 size() 而不加载所有学生。

所有您拥有的更简单的解决方案。

于 2013-11-12T20:17:07.200 回答
0

您说要切换到 EAGER 加载是因为延迟加载的性能很糟糕,但是使用 EAGER 加载您的性能将是相同的。你仍然会得到选择 n + 1 问题的解释,例如这里这里的解决方案。

为了提高性能,您需要修改 Hibernate 将生成的查询。通常我在 Hibernate 中做一个左外连接来获得这个,例如

sessionFactory.getCurrentSession().createCriteria(University.class)
.createAlias("students", "students_alias", JoinType.LEFT_OUTER_JOIN)
.list();

并且最好保持 Hibernate 默认的延迟加载。

于 2013-11-20T07:20:44.853 回答