Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Why is EclipseLink querying twice for the same entity?
Why is EclipseLink querying twice for the same entity? [message #909715] Fri, 07 September 2012 12:29 Go to next message
Alfredo Osorio is currently offline Alfredo Osorio
Messages: 6
Registered: March 2012
Junior Member
I am getting a strange behavior with EclipseLink. I added @BatchFetch(value=BatchFetchType.IN) to a relationship in this case to Address from Student. I am checking the generated SQL by EclipseLink when I query all students which are two and it is querying the same Address and a Student twice:

EclipseLink version 2.4.0

First the queries without BatchFetch:

SELECT ID, NAME FROM STUDENT
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [1]
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [2]

Expected SQL but now when I add the BatchFetch to Address relationship this is what is generated:

SELECT ID, NAME FROM STUDENT
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID IN (?,?))
bind => [1, 2]
SELECT ID, NAME FROM STUDENT WHERE (ID = ?)
bind => [2]
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [2]

Why is EclipseLink querying for a student if it already have all of them from the first query "SELECT ID, NAME FROM STUDENT" and also why is it querying ADDRESS if it already got it from SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID IN (1,2)) This strange behavior happens only when you add the BatchFetch annotation.

As you can see it is querying twice the Student and the Address.

SELECT ID, NAME FROM STUDENT WHERE (ID = ?)
bind => [2]

SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [2]

These are the classes:
Student.java:
@Entity
public class Student implements Serializable {
    private Long id;
    private String name;
    private List<Address> addresses = new ArrayList<Address>();
    private List<Classroom> classrooms = new ArrayList<Classroom>();


    public Student() {

    }

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQSTUDENTID")
    @SequenceGenerator(name="SEQSTUDENTID", sequenceName="SEQSTUDENTID", allocationSize=1)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(mappedBy="student", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @BatchFetch(value=BatchFetchType.IN)
    public List<Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(List<Address> addresses) {
        this.addresses = addresses;
    }

    @ManyToMany(mappedBy="students", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    public List<Classroom> getClassrooms() {
        return classrooms;
    }

    public void setClassrooms(List<Classroom> classrooms) {
        this.classrooms = classrooms;
    }

}


Address.java:

@Entity
public class Address implements Serializable {
    private Long id;
    private Student student;
    private String description;

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQADDRESSID")
    @SequenceGenerator(name="SEQADDRESSID", sequenceName="SEQADDRESSID", allocationSize=1)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @ManyToOne
    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

Test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/META-INF/application-context-root.xml"})
@Transactional
public class TestingFetch {

    @PersistenceContext
    private EntityManager entityManager;
    private Student student1;
    private Student student2;

    @Before
    public void setUp() {
        List<Student> students = new ArrayList<Student>();

        student1 = new Student();
        student1.setName("Alfredo Osorio");

        Address student1Address1 = new Address();
        student1Address1.setDescription("FirstAddressStudent1");
        student1Address1.setStudent(student1);
        student1.getAddresses().add(student1Address1);

        Address student1Address2 = new Address();
        student1Address2.setDescription("SecondAddressStudent1");
        student1Address2.setStudent(student1);
        student1.getAddresses().add(student1Address2);

        students.add(student1);

        student2 = new Student();
        student2.setName("Jorge Ramirez");
        students.add(student2);

        Address student2Address1 = new Address();
        student2Address1.setDescription("FirstAddressstudent2");
        student2Address1.setStudent(student2);
        student2.getAddresses().add(student2Address1);

        Address student2Address2 = new Address();
        student2Address2.setDescription("SecondAddressstudent2");
        student2Address2.setStudent(student2);
        student2.getAddresses().add(student2Address2);

        Classroom classroom1 = new Classroom();
        classroom1.setName("Mathematics");

        Classroom classroom2 = new Classroom();
        classroom2.setName("Physics");

        Classroom classroom3 = new Classroom();
        classroom3.setName("Chemistry");

        classroom1.getStudents().add(student1);
        student1.getClassrooms().add(classroom1);
        classroom1.getStudents().add(student2);
        student2.getClassrooms().add(classroom1);

        classroom2.getStudents().add(student1);
        student1.getClassrooms().add(classroom2);

        classroom3.getStudents().add(student2);
        student2.getClassrooms().add(classroom3);

        for (Student student : students) {
            entityManager.persist(student);         
        }

        entityManager.flush();
        entityManager.clear();
    }

    @Test
    public void testFetch1() {
        String jpql = "select m from Student m";
        Query query = entityManager.createQuery(jpql);
        List<Student> list = (List<Student>)query.getResultList();
    }
}

Re: Why is EclipseLink querying twice for the same entity? [message #909728 is a reply to message #909715] Fri, 07 September 2012 12:48 Go to previous message
Alfredo Osorio is currently offline Alfredo Osorio
Messages: 6
Registered: March 2012
Junior Member
It seems that the problem has something to do with the bidirectional relationship between Student and Address and the FETCH TYPE. If I change the fetch type to LAZY on the Student field of Address. I get these SQLs:
SELECT ID, NAME FROM STUDENT
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID IN (?,?))
bind => [1, 2]

These SQLs are correct. Anyway it seems like a bug to me because I shouldn't have to change the fetch type to avoid this situation.

[Updated on: Fri, 07 September 2012 12:49]

Report message to a moderator

Previous Topic:Suggestion: commit() method returning the number of committed.
Next Topic:Constant "Connection closed" errors in new app
Goto Forum:
  


Current Time: Thu Jul 31 13:47:48 EDT 2014

Powered by FUDForum. Page generated in 0.01516 seconds