JPA:基于多个子实体上的多个条件选择实体 [英] JPA: Selecting entities based on multiple criterions on multiple child entities

查看:125
本文介绍了JPA:基于多个子实体上的多个条件选择实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使以下方案正常工作时遇到问题.一个学生可以参加考试.一个学生随着时间的推移参加了几次测试,并为每项测试取得了分数.每个学生实体都有一个已完成的测试列表,它们映射为@OneToMany.

I have a problem getting the following scenario to work. A student can take tests. A student have over time taken a few tests and got a score for each test. Each student entity have a list of tests that they have completed mapped as @OneToMany.

现在,我想选择所有在一系列分组条件下均已完成测试的学生.例如,我想搜索所有具有以下条件的学生:

Now I want to select all students that have completed tests on a range of grouped criterions. I want for example to search for all students that have:

第1组:完成测试1"并获得"75到100"之间的分数

和/或

第2组:完成测试2"并获得"50到80"之间的分数

到目前为止,这是我所拥有的,但不能满足我的需要(无法通过多个参数进行搜索,这意味着我必须多次执行查询):

This is what I have so far but it does not do what I need (cannot search by multiple parameters meaning that I have to perform the query multiple times):

SELECT s FROM Student s JOIN s.tests t WHERE t.score BETWEEN :minScore AND :maxScore AND t.testName = :testName

有没有一种方法可以使用单个NamedQuery来实现我想要的?要检索所有已完成至少与上述参数组之一匹配的测试的学生?我一直在尝试连接,但一直在碰壁.

Is there a way to use a single NamedQuery to achieve what I want? To retrieve all Students that have completed a test that matches at least one of the parameter groups above? I've been experimenting with joins but keep running into the wall.

我在下面制作了一个示例代码框架,以说明我要执行的操作.

I made a sample code skeleton below to illustrate what I'm trying to do.

@Entity
@NamedQueries({
    @NamedQuery(name="Student.findStudentByParams", query="????????") // What should this query look like to satisfy the criteria? (see below for more detail)
})
public class Student {
    // .. Some other variables that are not relevant for this example

    @Id
    private String name;

    @OneToMany(fetch=FetchType.EAGER, mappedBy = "student")
    private List<Test> tests;

    // Setters and getters
}

@Entity
public class Test {
    private double score;
    private String testName;
    // .. Some other variables that are not relevant for this example

    @ManyToOne(cascade=CascadeType.ALL)
    private Student student;

    // Setters and getters
}

public class SearchParameters {
    private double minScore;
    private double maxScore;
    private String testName; 

    public SearchParameters(String minScore, String maxScore, String testName) {
        this.minScore = minScore;
        this.maxScore = maxScore;
        this.testName = testName;
    }

    // Setters and getters
}

public class MainClass {
    public static List<Student> getStudents(List<SearchParameters> searchParams) {

        // Database initialization stuff

        // What should the query look like to find all students that match any of the combined requirements in the searchParams list? 
        // Is it possible to do in a single query or should i make multiple ones?
        // What parameters should i set? Is it possible to put in the entire array and do some sort of join?

        // Retrieve all students which matches any of these search parameters:
        // Have either:
        //      Completed "Test 1" and got a score between 75 and 100
        // and/or:
        //      Completed "Test 2" and got a score between 50 and 80
        Query namedQuery = em.createNamedQuery("Student.findStudentByParams");
        namedQuery.setParameter(??); 

        return (List<Student>)namedQuery.getResultList();

    }
    public static void main() {
        List<SearchParams> searchParams = new ArrayList<SearchParams();
        searchParams.add(new SearchParameters(75,100, "Test 1"));
        searchParams.add(new SearchParameters(50,80, "Test 2"));

        // Retrieve all students which matches any of these search parameters:
        // Have either:
        //      Completed "Test 1" and got a score between 75 and 100
        // and/or:
        //      Completed "Test 2" and got a score between 50 and 80
        ArrayList<Student> students = getStudents(searchParams);
        for(Student s: students) // Print all user that match the criteria
        {
            System.out.println("Name: " + s.getName());
        }
    }   
}

推荐答案

您需要使用Criteria Builder(以及最终的规范元模型).

You need to use Criteria Builder (and eventually the canonical Metamodel).

尝试类似的方法(未经测试的代码):

Try something like this (code not tested):

EntityManager em;    // put here your EntityManager instance
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = cb.createQuery(Student.class);
Root<Student> student = cq.from(Student.class);
Predicate predicate = cb.disjunction();
for (SearchParams param : searchParams) {
    ListJoin<Student, Test> tests = student.join(Student_.tests);
    Predicate tempPredicate1 = cb.equal(tests.get(Test_.testName), param.getTestName());
    Predicate tempPredicate2 = cb.ge(tests.get(Test_.score), param.getMinScore());
    Predicate tempPredicate3 = cb.le(tests.get(Test_.score), param.getMaxScore());
    Predicate tempPredicate = cb.and(tempPredicate1, tempPredicate2, tempPredicate3);
    predicate = cb.or(predicate, tempPredicate);
}
cq.where(predicate);
TypedQuery<Student> tq = em.createQuery(cq);
return tq.getResultList();

这篇关于JPA:基于多个子实体上的多个条件选择实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆