Home » Eclipse Projects » EclipseLink » Problem with QueryHints.BATCH/FetchType.EAGER(Extra queries being generated despite QueryHints.BATCH being set)
Problem with QueryHints.BATCH/FetchType.EAGER [message #670987] |
Mon, 16 May 2011 13:02 |
Iain Messages: 2 Registered: May 2011 |
Junior Member |
|
|
Updated: Just discovered it only happens with FetchType.EAGER
I'm having problems modelling a parent/child relationship where the foreign key used by the child is part of the primary key of the child and batching is in use (the child links to the parent by holding the "parent ID", but also uses this "parent ID" as part of the child key.) I'm using EclipseLink 2.1.3.
I understand the way of doing this is to use the @IdClass attribute. This seems to work fine (I've put a minimal sample together - see code below), but I see odd behaviour when this is used in conjunction with the QueryHints.BATCH and FetchType.EAGER attribute.
When I don't use the batch attribute running the named query results in the following (two test entities exist):
SELECT ID, Name FROM Parent
SELECT ID, Name, ParentID FROM Child WHERE (ParentID = ?)
SELECT ID, Name, ParentID FROM Child WHERE (ParentID = ?)
This seems to make sense - one query to get the Parent objects (2 of these), followed by two subsequent queries to find the child objects.
However, when I use QueryHints.BATCH I see the following:
SELECT ID, Name FROM Parent
SELECT t0.ID, t0.Name, t0.ParentID FROM Child t0, Parent t1 WHERE (t0.ParentID = t1.ID)
SELECT ID, Name FROM Parent WHERE (ID = ?)
SELECT ID, Name, ParentID FROM Child WHERE (ParentID = ?)
The first two seem fine - load all the parents, then use a join to load all the children. Then it starts to look odd - it seems to be re-loading the parent, as if it were discovering the linkage in the other direction anew. It then proceeds to load the children of the parent again, looping around.
If I turn off FetchType.EAGER and use FetchType.LAZY it works as I would expect. Have I made a mistake with the annotations, or is this a bug?
@Entity(name="Parent")
@Table(name="Parent")
@NamedQueries({
@NamedQuery(
name=Parent.QUERY_LOAD_ALL,
query="SELECT p FROM Parent p",
hints = {
@QueryHint(name=QueryHints.BATCH, value = "p.children")
})
})
public static class Parent implements Serializable {
private static final long serialVersionUID = 7466207603877307115L;
public static final String QUERY_LOAD_ALL = "Parent.QueryLoadAll";
@Id
@Column(name="ID", nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@Column(name="Name", nullable=false)
private String name;
public Parent(String name) {
this.name = name;
this.children = new ArrayList<Child>();
}
protected Parent() { }
@OneToMany( mappedBy="parentId", fetch=FetchType.EAGER, cascade={CascadeType.ALL})
@PrivateOwned
private List<Child> children;
public List<Child> getChildren() {
return children;
}
public void addChild(Child child) {
children.add(child);
child.setParent(this);
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
@Embeddable
public static class ChildPK implements Serializable {
private static final long serialVersionUID = 6421137405830734689L;
@Column(name="ParentID", nullable=false)
private int parentId;
@Column(name="ChildID", nullable=false)
private int childId;
protected ChildPK() {
}
public ChildPK(int parentId, int childId) {
this.parentId = parentId;
this.childId = childId;
}
public int getParent() {
return parentId;
}
public int getChildId() {
return childId;
}
}
@Entity(name="Child")
@Table(name="Child")
@IdClass(ChildPK.class)
public static class Child implements Serializable {
private static final long serialVersionUID = -2482368855024769511L;
@Id
@JoinColumn(name="ParentID", referencedColumnName="ID")
Parent parentId;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="ID")
int childId;
@Column(name="Name", nullable=false)
private String name;
protected Child() {
}
public Child(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setParent(Parent parent) {
this.parentId = parent;
}
}
[Updated on: Mon, 16 May 2011 13:10] Report message to a moderator
|
|
|
Re: Problem with QueryHints.BATCH/FetchType.EAGER [message #671032 is a reply to message #670987] |
Mon, 16 May 2011 15:24 |
|
The problem with EAGER is that the relationship must be built. With batch fetching you are fetching the batch of objects with the relationship, so those batch objects must be built, since you then also have another cyclic EAGER parent relationship, it must then build that object, causing the select for its parent, as the parent has not been built yet.
In general I would always recommend using LAZY. For this situation you can resolve it by either using LAZY on the OneToMany, or the ManyToOne back, with both EAGER you are forcing the batch query instantiation.
If you require to make every relationship EAGER, then you could also try using join fetching, instead of batch fetching.
James : Wiki : Book : Blog : Twitter
|
|
| |
Goto Forum:
Current Time: Thu Apr 25 21:07:38 GMT 2024
Powered by FUDForum. Page generated in 0.03005 seconds
|