Today encountered a strange thing, using the Entitymanager.remove (entity) method to delete an entity, deleted, and do not error. Later through the multi-checks to solve the problem.
ERD
650) this.width=650; "src=" Http://s3.51cto.com/wyfs02/M00/7F/49/wKioL1cY4PXDaMjhAAA3p6ZllUk448.png "title=" Image 1.png "alt=" Wkiol1cy4pxdamjhaaa3p6zlluk448.png "/>
Entity definition
------------- First entity a ---------------@Entitypublic class A { @Id private Long id; @Column (nullable = false, unique = true, length = 60) private string internalkey; @ Onetomany (mappedby = "B", cascade = cascadetype.all, orphanremoval = true) private List<B> bs = new ArrayList<> (); &NBSP;&NBSP;&NBSP;&NBSP, ...} ------------- A second entity b ---------------@Entitypublic class B { @Id private Long id; @ManyToOne @JoinColumn (name = "A_internalkey", referencedcolumnname = " Internalkey ") private a a;   ...}
Data
Table a:id internalkey---------------------1 a1table b:id a_internalkey---------------------1 A12 A1
Problem
It is possible to delete record B (id:2) directly from table B based on years of experience in manipulating data with SQL scripts. There is no foreign key reference to table B on table A, so you can delete the data on table B directly, and the database management system will not be unhappy. However, when you use the Entitymanager Remove (entity) method in JPA to delete B (id:2), the problem occurs. Remove does not delete the B (id:2) record, not to mention the database records, even the SQL statements are not sent from the JEE container. And, even more deadly, no! Yes! Reported Wrong!
I made a replacement scheme and deleted B (id:2) directly with the JPQL statement, and the result was successful. Hehe, this is not the end, or I do not have to take the trouble to record this thing. After I removed B (id:2), I tried to save the changes to a, and then there was a problem. JPA Error, said B (id:2) can not find, I faint. What is the situation, B (Id:2) has been deleted by me, how to persist a when the JPA is to check a deleted object? I'm sure after I delete B (id:2) with JPQL, I manually removed B (id:2) from the A.bs collection, why is this B (id:2) haunting?
Analysis
After flipping through some of the documents, I was vaguely aware that the problem should be related to several states of the entity (especially the detached state) and the cache in the O/R mapping framework. To be blunt, that is where the program produces inconsistent data. In general, the resulting inconsistency may be related to the state, life cycle, or scope of access of the managed object. Then, in the case of JPA, the corresponding entity's lifecycle or access mechanism (caching mechanism) should be considered.
Continue to delve into the discovery that this issue is due to a combination of various aspects of the production.
First, the key point of the problem: A and B bidirectional onetomany (bidirectional one-to-many relationship).
This is a good understanding, just like the garbage collection mechanism in Java, the object being used is not GC. Similarly, the quoted child, which is this B (Id:2), has been quoted by a (id:1), how did JPA let you kill him?! Previously not mentioned, A (id:1) was read by JPA before removing B (id:2). A (id:1) should still be in the JPA cache when I try to delete B (id:2). according to the annotation annotation on the entity, A (id:1) should have both B (id:1), B (Id:2) references (that is, the two elements in the list<b> BS collection). The removal of JPA is for some protection and will not allow you to delete the quoted B (Id:2).
Of course, if you insist on deleting, you can use Entitymanager.createquery ("Delete from B WHERE b.id=2"). Executeupdate (); To forcibly delete the specified database record. Because CreateQuery (). Executeupdate () sends the specified SQL to the DBMS, and if there is an error, the exception is presented to the JPA framework by the DBMS through the underlying JDBC and eventually through Entitymanager. I just used this method to force B (id:2) to get rid of.
The next thing to say is factor two: the cache is inconsistent with the actual database
Look at the contents of the red section above. Did you think of anything? Before removing B (id:2), A (id:1) with references to B (id:1) and B (Id:2) remain in the cache. When B (Id:2) is forcibly removed by me with JPQL, there is no code to update a (ID:1) in the cache, so a (id:1) should have a reference to B (Id:2). Next, you want to persist a (id:1) change. Although I later manually made A.bs.remove (b (Id:2)) (the reference to B (Id:2) was removed from the BS collection), it is regrettable that a (id:1) is already in the detached state (i.e., the Free State, leaving a (id:1) that is already in a free State called a (ID : 1)). Changes to an object that is already in a free State are not mapped to the corresponding entity, in other words, a (id:1) in the JPA cache will not be updated, no matter what I do with a (id:1). And, when I tried to persist a free object A (id:1), JPA passed a (id:1). Equals (A (id:1)) comparison, that a (id:1) = = A (id:1), because the ID of two objects is the same, Hashcode, so JPA finds a (id:1) from the cache, tries to persist again, and the next thing doesn't need me to say, JPA error, and tip I can't find B (id:2). What Why are you looking for B (id:2)? Oh, that's because the cascade definition on a,)
Solution Solutions
I have two solutions here:
1, to update A as the starting point, after rejecting B (id:2), persist a. Due to the Cascade set on a, the JPA cascade deletes B (id:2) while updating a
2, you can forcibly delete B (Id:2), but before any action on a (id:1), go fecth A (id:1), that is, forcibly refresh the JPA cache.
I personally recommend the first option.
This article is from the "Bitterjava" blog, make sure to keep this source http://rickqin.blog.51cto.com/1096449/1766492
Entitymanager Unable to remove entity problem