EclipseLinkで奇妙な動作が発生します。@BatchFetch(value = BatchFetchType.IN)を、この場合は学生からの住所への関係に追加しました。2人のすべての学生にクエリを実行し、同じアドレスと1人の学生に2回クエリを実行すると、EclipseLinkによって生成されたSQLをチェックしています。
EclipseLinkバージョン2.4.0
まず、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]
SQLが必要ですが、BatchFetchとAddressの関係を追加すると、次のように生成されます。
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]
EclipseLinkが最初のクエリ「SELECTID、NAME FROM STUDENT」からすべての学生をすでに持っている場合、なぜEclipseLinkは学生をクエリするのですか。また、SELECT ID、DESCRIPTION、STUDENT_ID FROM ADDRESS WHERE(STUDENT_ID IN(1,2))この奇妙な動作は、BatchFetchアノテーションを追加した場合にのみ発生します。
ご覧のとおり、StudentとAddressの2倍のクエリを実行しています。
SELECT ID, NAME FROM STUDENT WHERE (ID = ?)
bind => [2]
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [2]
これらはクラスです:
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;
}
}
テスト:
@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();
}
}