Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
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 Go to next message
Iain  is currently offline Iain Friend
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 Go to previous messageGo to next message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

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
Re: Problem with QueryHints.BATCH/FetchType.EAGER [message #671066 is a reply to message #671032] Mon, 16 May 2011 16:39 Go to previous message
Iain  is currently offline Iain Friend
Messages: 2
Registered: May 2011
Junior Member
Thank you for the explanation James - that makes sense, although it sounds like this would make EAGER a problem with any kind of cyclic relationship? Adding
@ManyToOne(fetch=FetchType.LAZY)
to the Child object's parentId fixes the issue, as does using the LAZY setting.
Previous Topic:How to convert a jpql filter condition to Expression
Next Topic:Multi-column, one-to-one, JPA 2.0 @EmbeddedId using @MapsId fails with read-only on @JoinColum
Goto Forum:
  


Current Time: Fri Dec 19 10:50:54 GMT 2014

Powered by FUDForum. Page generated in 0.01883 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software