I have a Hibernate persist on an entity with primary key constructor, but it does not take effect in the database after something I don't know while I need it in some other methods
Here is my code:
Base_Document document = new Base_Document(workItem.getProcessInstanceId());
this.getEntityManager().persist(document);
this.getEntityManager().flush();
this.getEntityManager().close();
and some where else I have :
Object o = this.getEntityManager().find(Base_Document.class,
workItem.getProcessInstanceId());
where o is null. Any help?
my entity code :
#Entity
public class Base_Document implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Long processInstanceId;
private DocumentStatus status;
#ManyToOne
private Base_Roles creatorRole;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date createDate;
public Base_Document() {}
public Base_Document(Long processInstanceId) {
this.processInstanceId = processInstanceId;
this.createDate = new Date();
this.status = DocumentStatus.DRAFT;
try {
String currentUser = PublicUtils.getHttpServletRequest().getUserPrincipal().getName();
this.setCreatorRole(PublicUtils.getEntityManager().find(Base_Roles.class, currentUser));
} catch (PolicyContextException ex) {
Logger.getLogger(Base_Document.class.getName()).log(Level.SEVERE, null, ex);
}
}
public Long getId() {
return processInstanceId;
}
public void setId(Long id) {
this.processInstanceId = id;
}
public Long getProcessInstanceId() {
return processInstanceId;
}
public void setProcessInstanceId(Long processInstanceId) {
this.processInstanceId = processInstanceId;
}
public DocumentStatus getStatus() {
return status;
}
public void setStatus(DocumentStatus status) {
this.status = status;
}
public Base_Roles getCreatorRole() {
return creatorRole;
}
public void setCreatorRole(Base_Roles creatorRole) {
this.creatorRole = creatorRole;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
}
From Hibernate "persist" description:
However, it does not guarantee that the identifier value will be assigned to the persistent instance immediately
https://access.redhat.com/site/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Hibernate_Core_Reference_Guide/objectstate-makingpersistent.html
You can use "save()" if immediately search required.
Related
New to JPA and encountered an issue.
Basically I am creating this bean:
PurchaseOrderControlBean purchaseOrderControl = new PurchaseOrderControlBean();
and using setters in order to fill it with data.
While trying to persist data to my DB I get this exception:
java.lang.IllegalArgumentException: Object is not a known entity type.
My Entity:
#Entity
#Table(name = "IMS_PURCHASE_ORDER_CONTROL", schema = "IMS")
public class PurchaseOrderControlBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = -5801211822984821162L;
#Id
#Column(name = "ID")
private BigDecimal id;
#Id
#Column(name = "INSURED_ID")
private BigDecimal insuredId;
#Column(name = "PROCESS_TYPE")
private BigDecimal processType;
#Column(name = "PROCESS_KEY")
private String processKey;
#Column(name = "SUPER_ClLAIM_NUM")
private BigDecimal superClaimNum;
#Column(name = "PURCHASE_ORDER_NUM")
private BigDecimal processOrderNum;
#Column(name = "PURCHASE_ORDER_SERVICE_TYPE")
private BigDecimal PurchaseOrderServiceType;
#Id
#Column(name = "CONTRACTOR_ID")
private BigDecimal Contarctor_Id;
#Column(name = "OPEN_DATE")
#Temporal(TemporalType.TIMESTAMP)
private Date openDate;
#Column(name = "STATUS")
private BigDecimal status;
#Column(name = "EXECUTION_DATE")
#Temporal(TemporalType.TIMESTAMP)
private Date exccutionDate;
#Column(name = "TOTAL_DURATION_DAYS")
private BigDecimal totalDurationDays;
#Column(name = "TOTAL_DELAY_DAYS")
private BigDecimal totalDelayDays;
#Id
#Column(name = "UPDATE_USER_ID")
private BigDecimal updateUserId;
public BigDecimal getId() {
return id;
}
public void setId(BigDecimal id) {
this.id = id;
}
public BigDecimal getInsuredId() {
return insuredId;
}
public void setInsuredId(BigDecimal bigDecimal) {
this.insuredId = bigDecimal;
}
public BigDecimal getProcessType() {
return processType;
}
public void setProcessType(BigDecimal processType) {
this.processType = processType;
}
public String getProcessKey() {
return processKey;
}
public void setProcessKey(String processKey) {
this.processKey = processKey;
}
public BigDecimal getSuperClaimNum() {
return superClaimNum;
}
public void setSuperClaimNum(BigDecimal superClaimNum) {
this.superClaimNum = superClaimNum;
}
public BigDecimal getProcessOrderNum() {
return processOrderNum;
}
public void setProcessOrderNum(BigDecimal processOrderNum) {
this.processOrderNum = processOrderNum;
}
public BigDecimal getPurchaseOrderServiceType() {
return PurchaseOrderServiceType;
}
public void setPurchaseOrderServiceType(BigDecimal purchaseOrderServiceType) {
PurchaseOrderServiceType = purchaseOrderServiceType;
}
public BigDecimal getContarctor_Id() {
return Contarctor_Id;
}
public void setContarctor_Id(BigDecimal contarctor_Id) {
Contarctor_Id = contarctor_Id;
}
public Date getOpenDate() {
return openDate;
}
public void setOpenDate(Date openDate) {
this.openDate = openDate;
}
public BigDecimal getStatus() {
return status;
}
public void setStatus(BigDecimal status) {
this.status = status;
}
public Date getExccutionDate() {
return exccutionDate;
}
public void setExccutionDate(Date exccutionDate) {
this.exccutionDate = exccutionDate;
}
public BigDecimal getTotalDurationDays() {
return totalDurationDays;
}
public void setTotalDurationDays(BigDecimal totalDurationDays) {
this.totalDurationDays = totalDurationDays;
}
public BigDecimal getTotalDelayDays() {
return totalDelayDays;
}
public void setTotalDelayDays(BigDecimal totalDelayDays) {
this.totalDelayDays = totalDelayDays;
}
public BigDecimal getUpdateUserId() {
return updateUserId;
}
public void setUpdateUserId(BigDecimal bigDecimal) {
this.updateUserId = bigDecimal;
}
Persist Method:
public Object save(Object obj) throws TecnicalException {
EntityManager entityManager = null;
EntityTransaction updateTransaction = null;
Object object = null;
boolean success = false;
try {
entityManager = PersistenceUtil.getEntityManager(dbName);
updateTransaction = entityManager.getTransaction();
updateTransaction.begin();
object = entityManager.merge(obj);
success = true;
} catch (PersistenceException e) {
logger.error("Exception while trying to update object " + obj, e);
ErrorLogUtil.writeErrorLog(Application.PERSISTANCE, "mng", null, "BaseDAO-Exception while trying to update object " + obj, "");
throw new TecnicalException(e);
} finally {
if (success) {
try {
updateTransaction.commit();
} catch (Exception e) {
logger.error("Failed commit" + e);
throw new TecnicalException(e);
}
} else {
if (updateTransaction != null && updateTransaction.isActive()) {
updateTransaction.rollback();
}
}
if (entityManager != null) {
entityManager.close();
entityManager = null;
}
}
return object;
}
When debugging the exception occurs on
object = entityManager.merge(obj);
I cannot seem to understand what I am missing here.
I could add any more information if needed.
I saw similar issues on other threads, however, it did not help me.
Thanks
I'm trying to update a basic deletion timestamp using a JPA persistence class. Here's the code:
public void delete(Document document, EntityManager em, SessionContext ctx)
throws MyException {
try {
ctx.getUserTransaction().begin();
DocumentDB documentDB = em.find(WDSDocument.class, document.getId());
if (documentDB != null) {
em.lock(documentDB, LockModeType.WRITE);
documentDB.setDeletedAt(new Timestamp(System.currentTimeMillis()));
em.merge(documentDB);
em.flush(); // OptimisticLockException raised here
}
ctx.getUserTransaction().commit();
if (log.isDebugEnabled()) log.debug("DELETED " + document.getId());
} catch (Exception e) {
ctx.getUserTransaction().rollback();
throw new MyException(Utils.getError("ERR9", new String[] { "" + document.getId(), e.getMessage() }),
e);
}
}
The document with the same Id as document is already stored in a DB and I would like to update a single field.
The em.flush() line is raising the exception, as if another user (thread) was trying to update the same object, but this isn't the case in my application.
I've read about OptimisticLockException in JPA and I understand that it can be raised when the same user tries to update an object twice in a row, without flushing/committing to a DB first.
Apparently this error happens whenever I try to update the documentDB deletion timestamp for any object, so I guess there should be something inherently wrong with my delete() method that double updates the object itself. I was not able to troubleshoot it correctly so far.
EDITED
Here's my DocumentDB class
#Entity
#Table(name = "DOCUMENTS", schema = "WP")
public class DocumentDB extends AbstractEntity {
private static final long serialVersionUID = -98765134L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_DOCUMENT", nullable = false)
private int id;
#Column(name = "SOURCE")
private String source = null;
#Column(name = "CREATION_DATE")
private Date creationDate;
#Column(name = "TITLE")
private String title = null;
#Column(name = "AUTHOR")
private String author = null;
#Column(name = "URL")
private String url = null;
#Column(name = "DELETED_AT")
private Timestamp deletedAt = null;
#Override
public Integer getId() {
return id;
}
#Override
public void setId(int id) {
this.id = id;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Timestamp getDeletedAt() {
return deletedAt;
}
public void setDeletedAt(Timestamp deletedAt) {
this.deletedAt = deletedAt;
}
}
While its abstract superclass is:
#MappedSuperclass
public abstract class AbstractEntity implements Serializable {
private static final long serialVersionUID = -98765134L;
public abstract Integer getId();
public abstract void setId(int id);
/**
* Creator of the record
*/
#Column(name = "USER_CREATION", nullable = false)
protected String userCreation;
/**
* Timestamp of creation of the record
*/
#Column(name = "DATE_CREATION", nullable = false)
protected Timestamp dateCreation;
/**
* User of the last change of the record
*/
#Column(name = "USER_LAST_CHANGE", nullable = false)
protected String userLastChange;
/**
* Timestamp of the last change of the record
*/
#Column(name = "DATE_LAST_CHANGE", nullable = false)
protected Timestamp dateLastChange;
/**
* Progressive of the variation of the record:
* used in optimistic locking of entity manager
* to avoid conflicts in insert/update
*/
#Version
#Column(name = "PG_VER_REC", nullable = false)
protected int progressiveVariationRecord;
public String getUserCreation() {
return userCreation;
}
public void setUserCreation(String userCreation) {
this.userCreation = userCreation;
}
public Timestamp getDateCreation() {
return dateCreation;
}
public void setDateCreation(Timestamp dateCreation) {
this.dateCreation = dateCreation;
}
public String getUserLastChange() {
return userLastChange;
}
public void setUserLastChange(String userLastChange) {
this.userLastChange = userLastChange;
}
public Timestamp getDateLastChange() {
return dateLastChange;
}
public void setDateLastChange(Timestamp dateLastChange) {
this.dateLastChange = dateLastChange;
}
public int getProgressiveVariationRecord() {
return progressiveVariationRecord;
}
public void setProgressiveVariationRecord(int progressiveVariationRecord) {
this.progressiveVariationRecord = progressiveVariationRecord;
}
}
Would you please provide some guidance on the next steps to perform in order to understand better this issue?
UPDATE
I haven't found the root cause of the issue so far. I suspect that my implementation of EclipseLink JPA does weird things when updating entities inside a for loop.
Unfortunately at the moment I don't have the time and the resources to dig deeper and I am using Pessimistic Locking as a workaround. Hope to find the real problem sometime in the future.
I'm doing the below query to find records that are in a temp table and dont exist in master then insert the results to the master table
#Query(value = "select b from InboundTemp b where b.transactionId NOT IN (SELECT p2.transactionId FROM Inbound p2)")
ArrayList<InboundTemp> findMissing();
However if I pass a single result object to the JpaRepository save method (To update the master table)it does an update instead of an insert.
what would I be doing wrong?
import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;
#Entity
#Table(name="inbound_postpay_temp")
#NamedQuery(name="InboundPostpayTemp.findAll", query="SELECT i FROM InboundPostpayTemp i")
public class InboundPostpayTemp implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int id;
#Column(name="bill_ref_no")
private String billRefNo;
#Column(name="business_shortcode")
private String businessShortcode;
private byte clicked;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="created_at")
private Date createdAt;
private String kpresponse;
private String KPtransaction_id;
#Column(name="mpesa_sender")
private String mpesaSender;
private String msisdn;
#Column(name="Network")
private String network;
#Column(name="org_account_balance")
private float orgAccountBalance;
private String status;
#Column(name="transaction_amount")
private float transactionAmount;
#Column(name="transaction_id")
private String transactionId;
#Column(name="transaction_time")
private String transactionTime;
#Column(name="transaction_type")
private String transactionType;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="updated_at")
private Date updatedAt;
public InboundPostpayTemp() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getBillRefNo() {
return this.billRefNo;
}
public void setBillRefNo(String billRefNo) {
this.billRefNo = billRefNo;
}
public String getBusinessShortcode() {
return this.businessShortcode;
}
public void setBusinessShortcode(String businessShortcode) {
this.businessShortcode = businessShortcode;
}
public byte getClicked() {
return this.clicked;
}
public void setClicked(byte clicked) {
this.clicked = clicked;
}
public Date getCreatedAt() {
return this.createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public String getKpresponse() {
return this.kpresponse;
}
public void setKpresponse(String kpresponse) {
this.kpresponse = kpresponse;
}
public String getKPtransaction_id() {
return this.KPtransaction_id;
}
public void setKPtransaction_id(String KPtransaction_id) {
this.KPtransaction_id = KPtransaction_id;
}
public String getMpesaSender() {
return this.mpesaSender;
}
public void setMpesaSender(String mpesaSender) {
this.mpesaSender = mpesaSender;
}
public String getMsisdn() {
return this.msisdn;
}
public void setMsisdn(String msisdn) {
this.msisdn = msisdn;
}
public String getNetwork() {
return this.network;
}
public void setNetwork(String network) {
this.network = network;
}
public float getOrgAccountBalance() {
return this.orgAccountBalance;
}
public void setOrgAccountBalance(float orgAccountBalance) {
this.orgAccountBalance = orgAccountBalance;
}
public String getStatus() {
return this.status;
}
public void setStatus(String status) {
this.status = status;
}
public float getTransactionAmount() {
return this.transactionAmount;
}
public void setTransactionAmount(float transactionAmount) {
this.transactionAmount = transactionAmount;
}
public String getTransactionId() {
return this.transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public String getTransactionTime() {
return this.transactionTime;
}
public void setTransactionTime(String transactionTime) {
this.transactionTime = transactionTime;
}
public String getTransactionType() {
return this.transactionType;
}
public void setTransactionType(String transactionType) {
this.transactionType = transactionType;
}
public Date getUpdatedAt() {
return this.updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
}
The master class is the same
Below is the method that is persisting to dB
missing = temprepo.findMissing();
for (InboundPostpayTemp inboundPostpayTemp2 : missing) {
postpaytransaction.setBillRefNo(inboundPostpayTemp2.getBillRefNo());
postpaytransaction.setBusinessShortcode("");
// postpaytransaction.setClicked("0".t);
postpaytransaction
.setCreatedAt(new java.sql.Timestamp(inboundPostpayTemp2.getCreatedAt().getTime()));
postpaytransaction.setMpesaSender(inboundPostpayTemp2.getMpesaSender());
postpaytransaction.setMsisdn(inboundPostpayTemp2.getMsisdn());
postpaytransaction.setTransactionAmount(inboundPostpayTemp2.getTransactionAmount());
postpaytransaction.setTransactionId(inboundPostpayTemp2.getTransactionId());
postpaytransaction.setTransactionType("Paybill-Repost");
postpaytransaction.setStatus("CONFIRMED");
postpaytransaction.setTransactionTime(inboundPostpayTemp2.getTransactionTime());
//postpaytransactionx.add(postpaytransaction);
inboundpostpayrepo.save(postpaytransaction);
}
The only reason why JPA does an update instead of insert is that the Primary Key already exists in your persistence layer or your table. So kindly check or post your source code in order to review it and find what is wrong (if the issue is not in your data).
Now that you have updated the question with the source code, your bug is probably on the instantiation of the postpaytransaction object.
try to insert into your loop before everything else
postpaytransaction = new PostPayTransaction ()
I had the exactly same issue. My point was that the SpringBoot was automatically recreating the DB on startup, incorrectly creating the identity column in the table.
Look for spring.jpa.hibernate.ddl-auto.
Here is my code
VirsualPerson
public class VirsualPerson extends Person{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#PrimaryKeyJoinColumn(name="VIRSUALPERSON_ID")
private long virsualPersonId;
#ManyToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
#JoinTable(name="Anime_character",catalog="anime",joinColumns={
#JoinColumn(name="VIRSUALPERSON_ID",nullable=false)},inverseJoinColumns={#JoinColumn(name="ANIME_ID",nullable=false)})
private Set<Anime>animeCharacters=new HashSet<Anime>();
#OneToMany(fetch=FetchType.LAZY,mappedBy="charecter")
private Set<VirsualPeopleComment>comments=new HashSet<VirsualPeopleComment>();
public long getVirsualPersonId() {
return virsualPersonId;
}
public void setVirsualPersonId(long virsualPersonId) {
this.virsualPersonId = virsualPersonId;
}
public Set<Anime> getAnimeCharacters() {
return animeCharacters;
}
public void setAnimeCharacters(Set<Anime> animeCharacters) {
this.animeCharacters = animeCharacters;
}
public Set<VirsualPeopleComment> getComments() {
return comments;
}
public void setComments(Set<VirsualPeopleComment> comments) {
this.comments = comments;
}
}
VirsualPersonComment
#Entity
#Table(name="people_comment")
public class VirsualPeopleComment {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="peopleCommentId")
private long commentId;
#Column(name="content")
private String commentContent;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="POST_TIME")
private Date postTime;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="USER_ID")
private User commentUser;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="VIRSUALPERSON_ID")
private VirsualPerson charecter;
public long getCommentId() {
return commentId;
}
public void setCommentId(long commentId) {
this.commentId = commentId;
}
public String getCommentContent() {
return commentContent;
}
public void setCommentContent(String commentContent) {
this.commentContent = commentContent;
}
public Date getPostTime() {
return postTime;
}
public void setPostTime(Date postTime) {
this.postTime = postTime;
}
public User getCommentUser() {
return commentUser;
}
public void setCommentUser(User commentUser) {
this.commentUser = commentUser;
}
public VirsualPerson getCharecter() {
return charecter;
}
public void setCharecter(VirsualPerson charecter) {
this.charecter = charecter;
}
}
And here is the error
A Foreign key refering VirsualPerson from VirsualPeopleComment has the wrong number of column. should be 2
I want to know what's wrong with my annotations and thanks a lot
I guess you should specify #JoinColumn here as well:
#OneToMany(fetch=FetchType.LAZY,mappedBy="charecter")
private Set<VirsualPeopleComment>comments=new HashSet<VirsualPeopleComment>();
looks like it should be
#OneToMany(fetch=FetchType.LAZY,mappedBy="charecter")
#JoinColumn(name="peopleCommentId")
private Set<VirsualPeopleComment>comments=new HashSet<VirsualPeopleComment>();
Helo,
I have method
public void createContest(Contest c) {
session.beginTransaction();
session.persist(c);
session.getTransaction().commit();
logger.info("Contest saved successfully!");
}
I call it in one place with one object but this method save the object Contest to the database 4x. What could be the problem?
Here is Contest class:
#Entity
#Table(name = "Contest")
public class Contest implements java.io.Serializable {
#Id
#Column(name="CONTEST_ID", unique = true, nullable = false, precision = 5, scale = 0)
#GeneratedValue
private int id;
#Column(name="NAME")
private String name;
#Column(name="DATE_OF_EVENT")
private Date dateOfEvent;
#Column(name="REG_OPEN")
private Date regOpen;
#Column(name="REG_CLOSE")
private Date regClose;
#Column(name="REG_RESTRICTION")
private Boolean regRestriction;
#Column(name="CAPACITY")
private int capacity;
#OneToMany(mappedBy="upperContest")
private List<Contest> precontests;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name="UPPER_CONTEST_ID")
private Contest upperContest;
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name="MANAGING",
joinColumns={#JoinColumn(name="CONTEST_ID")},
inverseJoinColumns={#JoinColumn(name="PERSON_ID")})
private List<Person> managers;
#OneToMany(mappedBy="contest")
private List<Team> teams;
public Contest(String name, Date dateOfEvent, Date regOpen,
Date regClose, Boolean regRestriction) {
this.name = name;
this.dateOfEvent = dateOfEvent;
this.regOpen = regOpen;
this.regClose = regClose;
this.regRestriction = regRestriction;
this.precontests = new ArrayList<Contest>();
this.managers = new ArrayList<Person>();
this.teams = new ArrayList<Team>();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDateOfEvent() {
return dateOfEvent;
}
public void setDateOfEvent(Date dateOfEvent) {
this.dateOfEvent = dateOfEvent;
}
public Date getRegOpen() {
return regOpen;
}
public void setRegOpen(Date regOpen) {
this.regOpen = regOpen;
}
public Date getRegClose() {
return regClose;
}
public void setRegClose(Date regClose) {
this.regClose = regClose;
}
public Boolean getRegRestriction() {
return regRestriction;
}
public void setRegRestriction(Boolean regRestriction) {
this.regRestriction = regRestriction;
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public Contest getUpperContest() {
return upperContest;
}
public void setUpperContest(Contest c) {
this.upperContest = c;
}
public List<Contest> getPrecontests() {
return precontests;
}
public void addPrecontest(Contest e) {
this.precontests.add(e);
}
public void addManager(Person p){
this.managers.add(p);
}
public void addTeam(Team t){
this.teams.add(t);
}
public List<Person> getManagers(){
return managers;
}
}
And now I have to add some text because of restrictions of stackoverflow. Such Cool. Very wow.
You haven't posted the code where you instantiate Contest and populate its fields, but upperContest is probably the cause. You have CascadeType.ALL on the mapping, so you probably are persisting one contest which has a upper contest, thus actually persisting two instances because of cascade setting. Can't know for sure without that code.