Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Lazy fetched ManyToOne field of an embedded object of a newly persisted entity resets to null(Is it a bug?)
Lazy fetched ManyToOne field of an embedded object of a newly persisted entity resets to null [message #547594] Mon, 19 July 2010 02:32 Go to next message
Igor Mukhin is currently offline Igor Mukhin
Messages: 14
Registered: July 2009
Junior Member
Hello everybody

(EclipseLink 2.1 with static weaving)

These are my entities:

Simple entity with id and an embedded object:
@Entity
public class Entity1 implements Serializable {
	@Id private int id;
	@Embedded private Embedded1 embedded1;

	public int getId() {	return id;	}
	public void setId(int id) {	this.id = id;	}
	public Embedded1 getEmbedded1(){	return embedded1;	}
	public void setEmbedded1(Embedded1 embedded1) {	this.embedded1 = embedded1;	}
}


A embaddable with one ManyToOne with FetchType.LAZY field.
@Embeddable
public class Embedded1 implements Serializable {
	@ManyToOne(fetch=FetchType.LAZY)
	private Person person;

	public Embedded1() {	}
	public Embedded1(Person person) {	this.person = person;	}
	public Person getPerson() {	return person;	}
	public void setPerson(Person person) {	this.person = person;	}
}


And a Person entity
@Entity
public class Person implements Serializable {
  @Id private int id;
  private String name;

  ... getters / setters for id and name
}



Then the code
@Component("testim")
@Scope("request")
public class TestIMBean {
	@Autowired EntityManager em;

	private int entity1id;

	public String createEntity1() {
                           Person person = em.find(Person.class, 1);
		Entity1 e1 = new Entity1();
		e1.setId(entity1id);
		e1.setEmbedded1(new Embedded1(person));
		em.getTransaction().begin();
		em.persist(e1);
		em.getTransaction().commit();

		entity1id = e1.getId();
		return null;
	}

	public String readEntity1() {
		Entity1 e1 = em.find(Entity1.class, entity1id);
		Person person = e1.getEmbedded1().getPerson();
		if (person == null) {
			Faces.error("e1.getEmbedded1().getPerson() is null");
			return null;
		}

		System.out.println(person.getFirstname());

		Faces.info("Read. Person is " + e1.getEmbedded1().getPerson().getFirstname());
		return null;
	}
}



Then i call createEntity1() which creates an entity with an id from entity1id field. That works fine. (The transaction gets commit, which is important step)

Then i use call readEntity1() to read the entity. This entity will be read from EclipseLink cache fine, BUT wenn I call e1.getEmbedded1().getPerson() it returns null.


I found out that
1) if I clear the cache emf.getCache().evictAll(), the entity will be reread from the database and the problem field is fine.
2) this happen only to the newly persisted objects
3) if you remove FetchType.LAZY, it also works fine
4) if you move person field from Embedded1 directoctly to Entity1, it also works fine

So the removal of FetchType.LAZY in embedded object is the best workaround for us. But it is not the best for the performance.
Is it a bug or do I do something wrong?

Thanks

[Updated on: Mon, 19 July 2010 05:17]

Report message to a moderator

Re: Lazy ManyToOne field of an embedded object of a just persisted entity returns null [message #547609 is a reply to message #547594] Mon, 19 July 2010 03:10 Go to previous messageGo to next message
Igor Mukhin is currently offline Igor Mukhin
Messages: 14
Registered: July 2009
Junior Member
I also tried to put a breakpoint just before calling getPerson():

http://demo.web-dienstleister.de/bp1.png

The "Variables"-View shows that EclipseLink cleared (not filled in) the person field. And now it has no way to fill it, because it has neither personId nor person itself.

http://demo.web-dienstleister.de/bp2.png
Re: Lazy ManyToOne field of an embedded object of a just persisted entity returns null [message #547642 is a reply to message #547609] Mon, 19 July 2010 05:02 Go to previous messageGo to next message
Igor Mukhin is currently offline Igor Mukhin
Messages: 14
Registered: July 2009
Junior Member
I have debugged the source code of EclipseLink. I have looked into the code just after I call commit on the transaction as a create the entity1.

After EclipseLink posts the changes to the database (INSERT in this case), it also merges the changes to the internal cache.

As there is no object in the cache it creates a clone using _persistence_shallow_copy(), which simply copies values of all field to the new object. So both, the clone and the source, objects have the reference to the same embedded1 instance.

Then, on this line on screenshot, EclipseLink sets the person field to null.
http://demo.web-dienstleister.de/bp3.png

As this embedded1 object is references by both the source and the target variables, the reference to the person object is LOST!
Re: Lazy ManyToOne field of an embedded object of a just persisted entity returns null [message #547834 is a reply to message #547642] Mon, 19 July 2010 13:52 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris Delahunt
Messages: 1017
Registered: July 2009
Senior Member
Have you tried using your setPerson accessor method within the constructor instead of setting it directly to see if this resolves the problem?

Best Regards,
Chris
Re: Lazy ManyToOne field of an embedded object of a just persisted entity returns null [message #548018 is a reply to message #547834] Tue, 20 July 2010 09:01 Go to previous messageGo to next message
Igor Mukhin is currently offline Igor Mukhin
Messages: 14
Registered: July 2009
Junior Member
Chris Delahunt wrote on Mon, 19 July 2010 13:52
Have you tried using your setPerson accessor method within the constructor instead of setting it directly to see if this resolves the problem?

Best Regards,
Chris


This is an EclipseLink issue. I have created a bug
https://bugs.eclipse.org/bugs/show_bug.cgi?id=320233
Re: Lazy ManyToOne field of an embedded object of a just persisted entity returns null [message #550899 is a reply to message #547642] Wed, 04 August 2010 11:20 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

This reset is correct, but it should not be the same embeddable instance. After the shallow clone a clone of the embeddable should be merge into the clone.

I'm not sure how you could be getting the same embeddable instance in both clones.


James : Wiki : Book : Blog : Twitter
Re: Lazy ManyToOne field of an embedded object of a just persisted entity returns null [message #551026 is a reply to message #550899] Wed, 04 August 2010 17:44 Go to previous message
Igor Mukhin is currently offline Igor Mukhin
Messages: 14
Registered: July 2009
Junior Member
I have created a sample project that demostrates the behavior and attached it to the bug:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=320233

EclipseLink create a shallow copy of the embedded object, so both copies references the same ValueHolder that references the Person object.
Than reset() clears the reference in the ValueHolder, which results that the reference to the Person object gets lost completely.

My guess is that EclipseLink needs a fix, that should save the primary key of the Person in the ValidHolder bevor the reference gets reset.


[Updated on: Wed, 04 August 2010 17:45]

Report message to a moderator

Previous Topic:Equivalent of ROUND in criteria query in JPA 2
Next Topic:Eclipselink + c3p0
Goto Forum:
  


Current Time: Fri Aug 22 17:40:42 EDT 2014

Powered by FUDForum. Page generated in 0.07887 seconds