Persisting composite pojo in hibernate but inner pojo getting freshly persisted - spring

The situation is : I have a Pojo DEVICE, which has a pojo Namespace pojo inside. :
#Entity
#Table(name = "device")
public class Device implements java.io.Serializable {
private long deviceId;
private long timestamp;
private NamespaceMaster namespaceMaster;
..................
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "namespace_id")
#Cascade(value = CascadeType.ALL)
public NamespaceMaster getNamespaceMaster() {
return this.namespaceMaster;
}
When i am persisting Device, I am querying database to find the appropriate namespace and then setting the namespace pojo to device. Up to this part there is no isse.
NamespaceMaster namespaceMaster=null;
try {
namespaceMaster = namespaceDAOImpl.queryAllByName(namespace, AZURE_CLOUDTYPE).get(0);
} catch (DaoException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
LOG.info("Namespace object from cache :{}",namespaceMaster);
device.setNamespaceMaster(namespaceMaster);
Now when am trying persist Device, the namespace table in DB also has new row inserted with the same value that I initially queried namespace table. This is happening due to
#Cascade(value = CascadeType.ALL)
The reason is : Hibernate is unable to recognise the namespace object as already persisted one. So it cascades all the pojo inside and hense inserts a new one.
My question is simple. How to insert device object in table such that the namespace is not generated new. It is the one that is already present in namespace table. I tried removing #Cascade(value = CascadeType.ALL), but then i get a error :
object references an unsaved transient instance - save the transient instance before flushing
Note
I have added #version in NamespaceMaster table
#Version
private Long version;
private static final long serialVersionUID = 1L;
I am struck guys!! Please suggest.
Thanks in advance.

Solved the above issue.
I had inserted namespace_id(primary key for namespace table) as 0 for my data. May be hibernate is unable to understand 0 as the key and resolve in this situation. Guys be aware of this fact!!
I tried giving implementation for hashcode(),equals;#Version etc but nothing worked. updating my table primary key from 0 to a higher value worked!!
Anyways!!

Related

CRUDRepository unable to save modified entities

I'm trying to fetch some data from the database, update a field with some other entity and save it back to the DB, of course I've made sure that both the first entity and the entity that is going to be inserted are retrieved and fine, it is just thrown upon the save function invokation.
Here's the exception
[err] org.springframework.dao.DataIntegrityViolationException: Attempt to persist detached object "repository.entities.RequestEntity-0". If this is a new instance, make sure any version and/or auto-generated primary key fields are null/default when persisting.; nested exception is <openjpa-2.4.3-r422266:1833086 nonfatal store error> org.apache.openjpa.persistence.EntityExistsException: Attempt to persist detached object "repository.entities.RequestEntity-0". If this is a new instance, make sure any version and/or auto-generated primary key fields are null/default when persisting.
FailedObject: repository.entities.RequestEntity-0
The entity
#Entity
#Table(name="REQUEST")
public class RequestEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="REQUEST_ID")
private long requestId;
some other fields ....
//bi-directional many-to-one association to MStatus
#ManyToOne
#JoinColumn(name="STATUS")
private MStatus mStatus;
getters and setters here as well ..
}
And lastly, here's the code
private void doStuff() throws Exception {
List<RequestEntity> requestsList = requestRepo
.findByMStatusStatusContaining("TEXT");
RequestEntity requestItem;
if (requestsList.size() > 1 || requestsList.isEmpty()) {
throw new Exception("No requests found");
} else {
requestItem = requestsList.get(0);
}
requestItem.setMApprovalStatus(mapprovalStatus.findOne("TEXT_TWO"));
requestRepo.save(requestItem);
}

one-way one-to-many throws Hibernate Cannot add or update a child row: a foreign key constraint fails

I have an application that teaches the user how to play various card games. The data model that gets persisted consists of a TrainingSession with a uni-directional one-to-many relationship with the Hands.
[EDIT] To clarify, a Hand has no existence outside the context of a TrainingSession (i.e they are created/destroyed when the TrainingSession is). Following the principals of Data Driven Design, the TrainingSession is treated as an aggregate root and therefore a single spring-data CrudRepository is used (i.e., no repository is created for Hand)
When I try to save a TrainingSession using a CrudRepository, I get: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (blackjack.hand, CONSTRAINT FKrpuxac6b80xc7rc98vt1euc3n FOREIGN KEY (id) REFERENCES training_session (tsid))
My problem is the 'save(trainingSession)' operation via the CrudRepository instance. What I don't understand is why the error message states that FOREIGN KEY (id) REFERENCES training_session (tsid)). That seems to be the cause of the problem but I cant figure out why this is the case or how to fix it. The relationship is uni-directional and nothing in the Hand class refers to the TrainingSession.
The code, minus all the getters and setters, is:
#Entity
public class TrainingSession {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer tsid;
private String strategy;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="id")
private List<Hand> hands;
private int userId;
protected TrainingSession() {
}
public TrainingSession(int userId, Strategy strategy, List<Hand> hands) {
this.strategy = strategy.getClass().getSimpleName();
this.hands = hands;
this.userId = userId;
}
while Hand is
#Entity // This tells Hibernate to make a table out of this class
public class Hand {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int p1;
private String p1s;
private int p2;
private String p2s;
private int d1;
private String d1s;
private int trials;
private int score;
public Hand() {
}
You need to save your TrainingSession and Hand objects first before saving the adding the hand objects to TrainingSession.
TrainingSession ts1 = new TrainingSession();
trainingSessionManager.save(ts1);
Hand hand1 = new Hand();
handManager.save(hand1);
Hand hand2 = new Hand();
handManager.save(hand2);
ts1.gethands().add(hand1);
ts1.gethands().add(hand2)
trainingSessionManager.save(ts1);
If you check your database you will find 3 tables TrainingSession, Hand and TrainingSession_Hand, The TrainingSession_Hand table references to both TrainingSession and Hand both. Therefore you need to save TrainingSession and hand before saving the relationship.
Found the problem. I was assuming that when spring-data set up the DB tables, it was able to figure out and set up the uni-directional 1-to-many relationship. Apparently that isn't the case. When I configure the relationship as bi-directional everything seems to work.
To fix things I:
removed from TrainingSession the #joincolumn annotation for hands
in Hands I added a TrainingSession field with a #ManyToOne annotation:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "tsid", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private TrainingSession tsession;
I also added in the Hand class the getter/setter for tsession
I can now do a save of the entire aggregate construct using only a TrainingSessionRepository.

Persisting cyclic dependent Entities

I have to deal with cyclic dependent relations I cannot influence and I am fairly new to JPA.
So a Entity has members of the same Entity and I resolved that by:
#Entity
#Table("A")
public class A {
#ManyToMany
#JoinTable(name = "A_HAS_SUBAS",
joinColumns = {#JoinColumn(name = "A_ID")},
inverseJoinColumns = {#JoinColumn(name = "SUBA_ID")})
private Set<A> as;
}
When writing to the DB I have the problem that Hibernate seems to not know which A has to be persisted first. I tried to solve this by removing all relations from A, write to the DB and restore relations afterwards through hibernate.
This seems to work, but seems to fail if an A has no SubAs and this doesn't fit with my understanding of the issue. So I certainly be wrong somewhere.
The Entity without relations is persisted by an inner transaction:
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
private void immediatelySaveNewEntity(A entity) {
try {
if (!dao.entityExistsFromId((int) entity.getId())) { dao.save(entity); }
} catch (Exception e) {
e.printStackTrace();
}
}
As a result I get a
ORA-02291: integrity constraint (...) violated - parent key not found
I can circumvent this issue by removing constraints from the DB, but this is not my preferred way of dealing with this.
I don't see any #Id attribute declared in class A. I believe you might have removed it for brevity.
Can you try updating #ManyToMany to #ManyToMany(cascade=CascadeType.ALL) as below and try.
#Entity
#Table("A")
public class A {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name = "A_HAS_SUBAS",
joinColumns = {#JoinColumn(name = "A_ID")},
inverseJoinColumns = {#JoinColumn(name = "SUBA_ID")})
public Set<A> as;
}
Able to save it with below hibernate test code and should work with JPA as well.
Session sess = //Get Session
Transaction tx1 = sess.beginTransaction();
A a = new A();
a.as = new HashSet<>();
a.as.add(new A());
a.as.add(new A());
sess.persist(a);
tx1.commit();
Incase I got your test scenario wrong, posting your basic test scenario would help.
Well, this was kind of mindbending for me, but my approach was okay with a slight mistake.
I had cyclic dependent Entities. Before writing to the DB took place I removed all relations from the entity, saved it to the DB and restored the relationships afterwards as an update. This was okay, because in this manner I had all entities in the DB and could restore the cyclic dependencies with ease. I wish I could have gotten rid of them in the first place, but no.
The mistake was in the how I did that. With having a single Transaction the removal of the relations had no effect, because when the Entity with all its relations got finally persisted to the DB I had restored the previous state already.
I attempted to use a new Transaction with
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
but in the same Bean and how I learned the hard way the same transaction.
The hint came from Strange behaviour with #Transactional(propagation=Propagation.REQUIRES_NEW)
So I injected a new instance of the same bean and executed the new Transaction on this instance, with access to the proxy and well --it worked.

I need help for persisting into oracle database

There is a problem about generating id while persisting into database.
I added the following code to my jpa entity file, however I'm getting 0 for personid.
#Id
#Column(unique=true, nullable=false, precision=10, name="PERSONID")
#SequenceGenerator(name="appUsersSeq", sequenceName="SEQ_PERSON", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "appUsersSeq")
private long personid;
EjbService:
#Stateless
public class EjbService implements EjbServiceRemote {
#PersistenceContext(name = "Project1245")
private EntityManager em;
#Override
public void addTperson(Tperson tp) {
em.persist(tp);
}
}
0 is default value for long type. The id will be set after invoking select query for the related sequence, which commonly is executed when you persist the entity. Are you persisting the entity? In case yes, post the database sequence definition to check it.

JPA unable to assign a new persisted entity in a many to one relationship

I have to JPA Entities defined with a bidirectional relationship many to one, hereby:
#Entity
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="DEPARTAMENTO_ID_GENERATOR",sequenceName="DEPARTAMENTO_SEQ")
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="DEPARTAMENTO_ID_GENERATOR")
#Column(name="DEP_ID")
private long id;
#Column(name="DEP_DESC")
private String desc;
//bi-directional many-to-one association to Academico
#OneToMany(mappedBy="department")
private Set<Proffesor> proffesors;
//getters and setters
}
#Entity
#Table(name="ACADEMICOS")
public class Proffesor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="ACADEMICOS_ID_GENERATOR", sequenceName="ACADEMICOS_SEQ")
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="ACADEMICOS_ID_GENERATOR")
#Column(name="ACD_ID")
private long id;
#ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE})
#JoinColumn(name="ACD_DEPADSCRITO_DEP")
private Department department;
// getters and setters.
}
After in a transactional Spring service I have the next code to manipulate the entities in this way.
#Transactional (propagation=Propagation.REQUIRED)
public void createDepartmentWithExistentProffesor(String desc,Long idAvaiableProf) {
// new department
Department dep = new Department();
dep.setDesc(desc);
HashSet<Proffesor> proffesors = new HashSet<Proffesor>();
dep.setProffesors(proffesors);
// I obtain the correct attached Proffesor entity
Proffesor proffesor=DAOQueryBasic.getProffesorById(idAvaiableProf);
// I asign the relationship beetwen proffesor and department in both directions
dep.addProffesors(proffesor);
// Persists department
DAODataBasic.insertDepartment(dep);
// The id value is not correct then Exception ORA-0221
System.out.println("SERVICIO: Departamento creado con id: " + dep.getId());
}
As I said in the comments the id of the new Department persisted is not a real database id inside the transaction, then it is produced an exception
Exception in thread "main" org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
........
Caused by: java.sql.BatchUpdateException: ORA-02291: integrity restiction (HIBERNATE_PRB.FK_ACD2DEP) violated - primary key don't found
I've tried in a test, persist the new departmen entity with no relationship with Proffesor and I've seen that the id of the new department persisted entity has not a valid value inside the transaction but out of the transaction already the id has a correct value.
But I need the correct value inside the transaction.
Can anybody help me?
Thank you in advance.
try this
#OneToMany(mappedBy="department",cascade = CascadeType.PERSIST)
private Set<Proffesor> proffesors;

Resources