EntityManager trying to insert entities without being prompted

放肆的年华 提交于 2019-12-18 09:35:08

问题


Perhaps I'm over-simplifying this by only giving you a small snippet of code (and I'll post more if that is the case) but I figure, initially, less is better:

I have an entity of type Asset which has a field of type Location, which is also an entity. When I set the Location of an Asset I must also set the Location of its children.

Location location = asset.getLocation();
em.merge(location);
em.flush();

childAsset.setLocation(asset.getLocation());
em.flush();

When I run flush(), I get the following exception:

Internal Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (SWRADMIN.LOCATION_PK) violated

My question is...why is this Location object even trying to be persisted? All I'm doing is setting a variable in an entity.

This was working fine before, but we just switched to using Eclipselink and Java EE 6 and this problem popped up.

Solution?: I used the idea of "detaching" from below and made the following change:

Location location = asset.getLocation();

em.detach(childAsset);
childAsset.setLocation(asset.getLocation());
em.merge();
em.flush();

and it worked! I'm confused as to why, though...you would think the auto-syncing would do the same thing.


回答1:


If the object is in managed state, then entity manager will synchronize it with the underlying database by persisting the object implicitly (probably at the end of the transaction) or explicitly when you call em.flush() method.

You can use em.detach(entity) to detach a single entity or em.clear() to detach all the entities. Then the changes being made on an entity/entities will not get reflected in the database.

To better handle this, you can use BMT (Bean Managed Transaction), where you have to handle the entity persistence, transaction manually.

Edit :

Location location = asset.getLocation();
childAsset.setLocation(location);
em.merge(childAsset);
em.flush();



回答2:


So, the location is an existing location, or a new object?

How was it read, was it read from another transaction or entity manager or detached in some way? If so, then you need to re-read (find) or merge it.

If it is new and related to a managed object, then yes, flush must write it.




回答3:


From the code, it looks like you are using the unmanaged version of location and associating that to the ChildAsset. If your childAsset->Location relation is marked cascade persist, then the spec requires perist will be called on Location on flush or commit. Since Location is not a managed object, it requires an exception on persist.

When Location is managed (such as when you call merge on ChildAsset or if you had used the managed instance of Location returned from the em.merge(location); call), the persist operation on ChildAsset->Location is a no-op.

Do not associate unmanaged entities to relationships marked cascade persist.



来源:https://stackoverflow.com/questions/8071673/entitymanager-trying-to-insert-entities-without-being-prompted

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!