Merge and saveOrUpdate of updated entity throws constraintViolationException - java

I have an entity which contains a Map:
#OneToMany(fetch = FetchType.EAGER)
#JoinTable(name = "matrix_columns", joinColumns = Array(new JoinColumn(name = "id")))
#MapKey(name="tenor")
#Fetch(value = FetchMode.SELECT)
#Access(AccessType.PROPERTY)
def getInputMapNative: java.util.Map[Int,Column] = inputMap
And the Columncontains an Array
#(OneToMany #field)(cascade = Array(CascadeType.ALL))
#OrderColumn(name = "input_index")
#Fetch(value = FetchMode.SELECT)
var inputs:Array[Input] = _
Because I am stucked with Hibernate 3.6 and of this bug Failed to lazily initialize a collection, no session or session was closed (despite eagerly fetching), I tried to implement as a workaround the following:
I merge and save the columns
I update the map and merge and save the parent entity
(Since I can't rely on Hibernate cascading)
However, I still get an exception which I am not ready to solve
09:41:26.160 [GS-Notifier-pool-6-thread-2] ERROR o.h.util.JDBCExceptionReporter - Duplicate entry '781' for key 'inputs_id'
09:41:26.167 [GS-Notifier-pool-6-thread-2] ERROR o.h.e.d.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not insert collection: [Column.inputs#69]
This is my code that I would like to use both for creating or saving a new matrix in the database
val mergedColumns = matrix.getInputMap.map {
case(tenor,column) =>
column.inputs foreach{
item =>
val mergedItem = session merge item
session saveOrUpdate mergedItem
}
(tenor, (session merge column).asInstanceOf[Column])
}
matrix.setInputMapNative(mergedColumns)
val mergedMatrix = session merge matrix
session saveOrUpdate mergedMatrix
transaction.commit()

The exception is related to the uniqueness of the primary key inputs_id. Hibernate tries to insert the same entry twice, so I guess your way to merge and save the columns and update the map is the problem here.
Please consider Session.saveOrUpdate.
To get a better answer, please provide additional information like the code snippet you use to insert the new entry.

Related

JPA ObjectOptimisticLockingFailureException on an Insert sql execution followed by an Update sql execution

I'm using Spring-data-jpa with Kotlin and I faced this error:
org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed
Here is my parent entity (unnecessary parts are omitted):
#Entity
class Parent(
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
#OneToMany(mappedBy = "parent", cascade = [CascadeType.ALL], orphanRemoval = true)
val children: MutableList<Child> = mutableListOf()
) {
fun addChild(child: Child) {
this.children.add(child)
child.parent = this
}
}
Here is my child entity (omitted too):
#Entity
#Table(uniqueConstraints = [UniqueConstraint(columnNames = ["parent_id"])]
class Child(
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
) {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parent_id")
lateinit var parent: Parent
}
Transactional code is simple as follows:
#Transactional
fun saveChildren() {
...
val parent: Parent = parentRepo.findById(parentId)
parent.addChild(Child())
parent.addChild(Child())
validateSavedChildren() // select all children data to validate for some business reason
parentRepo.save(parent)
}
I turn on the sql log for debugging and the sqls are like (It assumes the parent's id = 4):
insert into
child
(... parent_id)
values
(... 4)
enter code here
...
select
.... parent_id
from Child
where parent_id = 4
...
update Child
set
parent_id = 4
...
where id = 1
The query parameters are just correct. As I guess, the error occurred by the last update sql and also know what the error means. I think the data in insert sql is not yet visible when the update sql is executed. Why I'm thinking this way is because I tried to reproduce the error with debug mode with my IDE(IntelliJ) and I executed the codes line by line, and the error is disappeared. Is this common case in JPA??
What I really wonder is the reason why the update sql is executed. It seems useless because the setting data in update sql is just the same as insert sql. After some Internet research, I found out some cases that update happens after insert, but none of them fits my case.
I also tried to change one line of code:
parentRepo.saveAndFlush(parent)
It made the upate sql disappear and the error is gone forever.
Why does this happen?? What am I missing??
UPDATE
Here is the function validateSavedChildren code:
fun validateSavedChildren() {
val parents: List<Parant> parentRepo.findAll() // it select all parents in DB
var childrenCount = 0
parents.forEach { parent ->
childrenCount += parent.children.size
}
if (childrenCount > CHILDREN_LIMIT) {
throw ChildrenCountExceededLimitException()
}
}
Following a comment by #XtremeBaumer, It seems like the above function has the key point because the update sql execution is removed by erasing the above function call.

Primary key not returned in OneToOne join fetch in eclipselink

I have an issue join fetching in case of OneToOne relation in the same class. Example follows:
class Data {
...
#Id
#Column(name = "DATA_ID")
Long id;
#Column(name = "DATA_OWNER_ID")
#ForeignKey(entityClass = Owner.class)
Long ownerId;
#Column(name = "DATA_RELATED_ID")
#ForeignKey(entityClass = Data.class)
Long relatedDataId;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "DATA_RELATED_ID", referencedColumnName = "DATA_ID", insertable = false, updatable = false)
Data relatedData;
}
I want to select data based on some conditions, while also fetching/initialising the "relatedData", all in one JPQL query:
SELECT owner.something1, data
FROM Data data
JOIN Owner owner on data.ownerId = owner.id
JOIN FETCH data.relatedData
WHERE data.something2 = :expectedSomething2
Executing that JPQL query throws an exception:
Query: ReadObjectQuery(name="relatedData" referenceClass=Data)|Exception:
javax.persistence.PersistenceException: Exception [EclipseLink-6044] (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.QueryException
Exception Description: The primary key read from the row [DatabaseRecord(
DATA_X => something
DATA_Y => something2
...
)] during the execution of the query was detected to be null. Primary keys must not contain null.
Which is somewhat true, as there is no DATA_ID column listed. Changing JOIN FETCH to LEFT JOIN FETCH returns both owner.something1 and data, but the relatedData object is null (relatedDataId is not null).
I can see, that the id for relatedData is returned from DB, but eclipselink trims it in valueFromRowInternalWithJoin and trimRowForJoin methods.
The Id column name attribute value is the reason of this exception. Same issue found in eclipselink version 2.3.2 but it works fine in version 2.0.0
Try with this entry :
eclipselink.jpa.uppercase-column-names=true
OR Try with upper and lower case one by one which on will work for you.
#Id
#Column(name = "UUID") // UUID - uppercase/lowercase one by one
Long id;
I've somehow resolved this issue, but haven't had the time to correctly identify the cause. Final (working) version differences are:
I could've forgotten to add get/set for relatedData
I have specified targetEntity = Data.class in #OneToOne
Fetch is now a LEFT JOIN FETCH and appears before JOIN Owner owner

Delete all rows from a mysql table

I'm trying to delete all the records from a MySQL table (46 records).
The code I have tried. Any suitable answer?
Session hs = connection.NewHibernateUtil.getSessionFactory().openSession();
Criteria cr = hs.createCriteria(Bookmark.class);
Bookmark b;
List<Bookmark> li = cr.list();
for (Bookmark s : li) {
b = new Bookmark();
b.setId(s.getId());
Transaction tr = hs.beginTransaction();
hs.delete(b);
tr.commit();
hs.flush();
hs.close();
}
Error
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [mypojos.Bookmark#7]
You cant delete objects like that. You would first have to get the object from db and then you can delete using hs.delete(b); this is usually used when you have to cascade changes to associated objects.
Best approach in this case is to use HQL query something like this.
String stringQuery = "DELETE FROM tablename";
Query query = session.createQuery(stringQuery);
query.executeUpdate();

How to update a JPA entity using Querydsl?

I am trying to query JPA with Querydsl (4.1.4) as written here
http://www.querydsl.com/static/querydsl/latest/reference/html/ch02.html#jpa_integration . I use Hibernate (5.2.12.Final) as the JPA backend. I generate Querydsl query types from the JPA annotated classes using the apt-maven-plugin with the com.querydsl.apt.jpa.JPAAnnotationProcessor processor.
I have an issue while updating an entity : the updated value does not show up in the Java code. Here is the relevant code snippet that updates a boolean property (named success) in the Entity :
final EntityManagerFactory entityManagerFactory = PersistenceTestUtils.buildEntityManagerFactory();
final EntityManager entityManager = entityManagerFactory.createEntityManager();
final EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
final QJpaUpdateRound qJpaUpdateRound = QJpaUpdateRound.jpaUpdateRound;
final JPQLQueryFactory queryFactory = new JPAQueryFactory(entityManager);
final QJpaUpdateRound qJpaUpdateRound = QJpaUpdateRound.jpaUpdateRound;
final JPQLQueryFactory queryFactory = new JPAQueryFactory(entityManager);
final long roundId = 3L;
System.out.println("Original " +originalRound);
queryFactory //
.update(qJpaUpdateRound) //
.set(qJpaUpdateRound._success, true) //
.where(qJpaUpdateRound._id.eq(roundId)) //
.execute();
// entityManager.clear(); // Workaround
// Fetch the updated value
final UpdateRound updatedRound = queryFactory //
.selectFrom(qJpaUpdateRound) //
.where(qJpaUpdateRound._id.eq(roundId)) //
.fetchOne();
transaction.commit();
System.out.println("Updated "+ updatedRound);
This prints :
Original JpaUpdateRound{id=3; instant=2017-11-06T19:27:01.141Z;
success=false} Updated JpaUpdateRound{id=3;
instant=2017-11-06T19:27:01.141Z; success=false}
Also, an identity test on originalRound and updatedRound shows that both variables are the same instance.
I checked in the database : the value is really updated. And if I uncomment the following line
entityManager.clear(); // Workaround
The program prints
Original JpaUpdateRound{id=3; instant=2017-11-06T19:39:01.038Z;
success=false} Updated JpaUpdateRound{id=3;
instant=2017-11-06T19:39:01.038Z; success=true}
which is the result I expect.
It seems that the entity cache does not get updated when the Querydsl update is performed. Thus, it only returns the original Java object.
Why ? How can I synchronize the JPA backend and Querydsl ?
It appears there is no other way than manually tell the entity manager that it should refresh its data. Whether using entityManager.refresh(entity) on each entity that needs to be reloaded from the database; whether by clearing the whole entity manager cache by calling entityManager.clear().
See Force refresh of collection JPA entityManager

Caused by: org.hibernate.MappingException: Repeated column in mapping for entity

I am beginner in handling JPA with maven and JBOSS, with Restful to make my application I have the following problem arose me doing DEPLOY
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: com.company.test_resources_war_1.0-SNAPSHOTPU] Unable to build EntityManagerFactory
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: database.Photo column: fid_module (should be mapped with insert = \ "false \" update = \ "false \") "}}
Not that step, check all posles solutions, but did not find anything, can someone help me??
Thanks in advance
Below I show the SQL code in postgres that I have and I did the mapping.
I have three tables (activity, event and photo) where one of them (photo) refers to the other two (activity and event) but in a single column (photo.fid_module)
SQL Code (enginer database-->Postgresql):
CREATE TABLE activity (
id_activity integer not null,
name character varying(150),
description text,
CONSTRAINT id_activity_pk PRIMARY KEY (id_activity)
)
CREATE TABLE event (
id_event integer not null,
name character varying(150),
description text,
date timestamp without time zone,
CONSTRAINT id_event_pk PRIMARY KEY (id_event)
)
CREATE TABLE photo(
id_photo integer not null,
path character varying(150),
fid_module integer not null,
CONSTRAINT id_photo_pk PRIMARY KEY (id_photo),
CONSTRAINT fk_photo_activity FOREIGN KEY (fid_module)
REFERENCE activity (id_activity) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_photo_event FOREIGN KEY (fid_module)
REFERENCE event (id_event) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
Now the mapping I did with the help of Netbenas and gave me the following code (I did the mapping for the three tables, but in presenting me the problem is in the class Photo.java).
#Entity
#Table(name = "photo")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "photo.findAll", query = "SELECT p FROM Photo p"),
#NamedQuery(name = "photo.findByFidPhoto", query = "SELECT p FROM Photo p WHERE p.fidphoto = :fidphoto"),
#NamedQuery(name = "photo.findByIdPhoto", query = "SELECT p FROM Photo p WHERE p.idphoto = :idphoto")})
public class Photo implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_photo")
private Integer idPhoto;
#Column(name = "path")
private Recurso fidPath;
#JoinColumn(name = "fid_module", referencedColumnName = "id_activity")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private SliderWebHome fidModule;
#JoinColumn(name = "fid_module", referencedColumnName = "id_event")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private Publicacion fidModule1;
public ModuloRecurso() {
}
.......
}
I am using JPA for persistence (but do mvn clean install and mvn jboss-as: deploy several pulls me hibernate dependencies) could anyone tell me what is my mistake or could solve this problem. Thank you.
You have two column mapped with the same name
#JoinColumn(name = "fid_module", referencedColumnName = "id_activity")
#JoinColumn(name = "fid_module", referencedColumnName = "id_event")
Change one of the name attribute!
Looking in your exception, you can read:
Repeated column in mapping for entity
As noted in another answer, your Java code specifies the same join-column name for two fields, which can't work.
If this Java code is generated by a netbeans mapping tool, as it seems from your note
Now the mapping I did with the help of Netbenas and gave me the following code ...
the bad Java mapping is probably caused by a bad combination of constraints in your SQL.
You have in your definition of the photo table:
CONSTRAINT fk_photo_activity FOREIGN KEY (fid_module)
REFERENCE activity (id_activity) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_photo_event FOREIGN KEY (fid_module)
REFERENCE event (id_event) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
which attempts to make the column fid_module a foreign key referencing activity and also a foreign key referencing event, which can't work.
If you need foreign keys from photo to both of those tables, you'll need to use two different columns.

Categories

Resources