Reputation: 5331
I have form where I have decision select field like OrganizationalCell
: When I choose one option f.e: OrganizationalCellUnit
, I have to atach another input with entity OrganizationalCellUnit
, which is mandatory only in that configuration.
When I choose other value, this one isnt (OrganizationalCellUnit
) mandatory anymore.
I have my entity that I am trying to persist:
@ManyToOne(cascade = CascadeType.MERGE)
public OrganizationalCell organizationalCell;
@ManyToOne(cascade = CascadeType.MERGE)
@Nullable
public OutPatientClinic outPatientClinic;
@ManyToOne(cascade = CascadeType.MERGE)
@Nullable
public Workshop workshop;
@ManyToOne(cascade = CascadeType.MERGE)
public OrganizationalCellUnit organizationalCellUnit = null;
/** The clinic. */
@ManyToOne(cascade = CascadeType.MERGE)
public models.Clinic clinic;
/** The unit. */
@ManyToOne(cascade = CascadeType.MERGE)
public models.Unit unit;
And I am getting an error:
Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: models.MedicalIncident.organizationalCellUnit -> models.OrganizationalCellUnit
In db these fields allow nullabe value.
How to make this field not mandatory, and make hibernate put null value in db
---Update---- After updating CascadeType to all on that Many to one relation I have this error:
play.api.Application$$anon$1: Execution exception[[ConstraintViolationException: Validation failed for classes [models.OrganizationalCellUnit] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='error.required', propertyPath=updateUser, rootBeanClass=class models.OrganizationalCellUnit, messageTemplate='error.required'}
ConstraintViolationImpl{interpolatedMessage='error.required', propertyPath=name, rootBeanClass=class models.OrganizationalCellUnit, messageTemplate='error.required'}
ConstraintViolationImpl{interpolatedMessage='error.required', propertyPath=creationUser, rootBeanClass=class models.OrganizationalCellUnit, messageTemplate='error.required'}
]]]
at play.api.Application$class.handleError(Application.scala:293) ~[play_2.10-2.2.4.jar:2.2.4]
at play.api.DefaultApplication.handleError(Application.scala:399) [play_2.10-2.2.4.jar:2.2.4]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:264) [play_2.10-2.2.4.jar:2.2.4]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:264) [play_2.10-2.2.4.jar:2.2.4]
at scala.Option.map(Option.scala:145) [scala-library.jar:na]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3.applyOrElse(PlayDefaultUpstreamHandler.scala:264) [play_2.10-2.2.4.jar:2.2.4]
Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [models.OrganizationalCellUnit] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='error.required', propertyPath=updateUser, rootBeanClass=class models.OrganizationalCellUnit, messageTemplate='error.required'}
ConstraintViolationImpl{interpolatedMessage='error.required', propertyPath=name, rootBeanClass=class models.OrganizationalCellUnit, messageTemplate='error.required'}
ConstraintViolationImpl{interpolatedMessage='error.required', propertyPath=creationUser, rootBeanClass=class models.OrganizationalCellUnit, messageTemplate='error.required'}
]
at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:159) ~[hibernate-core-4.2.0.CR1.jar:4.2.0.CR1]
at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:94) ~[hibernate-core-4.2.0.CR1.jar:4.2.0.CR1]
at org.hibernate.action.internal.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:178) ~[hibernate-core-4.2.0.CR1.jar:4.2.0.CR1]
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:75) ~[hibernate-core-4.2.0.CR1.jar:4.2.0.CR1]
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362) ~[hibernate-core-4.2.0.CR1.jar:4.2.0.CR1]
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:203) ~[hibernate-core-4.2.0.CR1.jar:4.2.0.CR1]
--- Edit Added
public class OrganizationalCellUnit extends GenericDictionary<OrganizationalCellUnit> {}
@MappedSuperclass
public abstract class GenericDictionary<T extends Generic<T>> extends Generic<T> {
@Required
public String name;
@Required
public boolean active = true;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean getActive() {
return active;
}
public void setActive(boolean stat) {
this.active = stat;
}
/**
* Options.
*
* @return the map
*/
public Map<String, String> getOptions() {
return getOptions(getList());
}
public Map<String, String> getOptions(List<T> list) {
LinkedHashMap<String, String> options = new LinkedHashMap<String, String>();
for (T e : list) {
GenericDictionary<?> entity = (GenericDictionary<?>) e;
if(entity.active==true) {
options.put(e.id.toString(), entity.name);
}
}
return options;
}
public void on() {
this.active = true;
update();
}
public void off() {
this.active = false;
update();
}
public abstract String getFieldDescription(String name);
@Override
public boolean equals(Object other) {
if (other == null) return false;
if (other == this) return true;
if (!(other instanceof GenericDictionary))return false;
GenericDictionary<?> otherMyClass = (GenericDictionary<?>) other;
return name.equals(otherMyClass.name);
}
@MappedSuperclass
public abstract class Generic<T extends Generic> {
@Transient
public Class<T> entityClass;
Generic() {
entityClass = ((Class) ((Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]));
}
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public Long id;
@ManyToOne(cascade = CascadeType.MERGE)
@Constraints.Required
public User creationUser;
@ManyToOne(cascade = CascadeType.MERGE)
@Constraints.Required
public User updateUser;
@Constraints.Required
public String creationDate = Index.getDate(null);
@Constraints.Required
public String updateDate = Index.getDate(null);
public User getCreationUser() {return creationUser;}
public void setCreationUser(User user) {this.creationUser = user;}
public void setCreationUser() {this.creationUser = User.getCurrentUser();}
public User getUpdateUser() {return updateUser;}
public void setUpdateUser(User user) {this.updateUser = user;}
public void setUpdateUser() {this.updateUser = User.getCurrentUser();}
public String getCreationDate() {return creationDate;}
public void setCreationDate(String creationDate) {this.creationDate = creationDate;}
public String getUpdateDate() {return updateDate;}
public void setUpdateDate(String updateDate) {this.updateDate = updateDate;}
public T getBy(Long id) {
return JPA.em().find(entityClass, id);
}
public List<T> getList() {
return (List<T>) JPA.em().createQuery("FROM " + entityClass.getSimpleName()).getResultList();
}
public List<T> getByUser_id(Long id) {
List<T> entities = new ArrayList<T>();
TypedQuery<T> query = JPA.em().createQuery("SELECT r FROM " + entityClass.getSimpleName() + " r WHERE r.user.id != :user_id", entityClass).setParameter("user_id", id);
try {
entities = query.getResultList();
} catch (NoResultException e) {
entities = null;
}
return entities;
}
public List<T> getByParameterAndValue(String parameter, String value) {
List<T> entities = new ArrayList<T>();
String sqlString = "SELECT e FROM " + entityClass.getSimpleName() + " e WHERE e."+ parameter +" != :value";
TypedQuery<T> query = JPA.em().createQuery(sqlString, entityClass).setParameter("value", value);
try {
entities = query.getResultList();
} catch (NoResultException e1) {
entities = null;
} catch (Exception e) {
Index.toLog("error","Unsupported error in Generic model class in " + entityClass);
}
return entities;
}
@PrePersist
public void prePersist() {
Logger.warn(this.toString());
setCreationDate(Index.getDate(null));
preUpdate();
}
@PreUpdate
public void preUpdate() {
Logger.debug(this.toString());
setUpdateDate(Index.getDate(null));
}
public void toDataBase() {
System.out.println("------------------Trying to persist------------------------");
JPA.em().persist(this);
}
public void update() {
JPA.em().merge(this);
}
public void delete() {
JPA.em().remove(this);
}
/**
* A Generic toString method that can be used in any class.
* uses reflection to dynamically print java class field
* values one line at a time.
* requires the Apache Commons ToStringBuilder class.
*/
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
// @Override
// public int hashCode() {
// return id.hashCode();
// }
}
Upvotes: 1
Views: 1553
Reputation: 2505
I had the same problem, and it turned out (at least in my case) that this was Play's fault - I can see you using Play as well.
ModelObject object = form.get()
Even if organizationalCell field is not passed from the form, Play actually creates a dummy model object (of type OrganizationalCellUnit in your case). So object.organizationalCell is not null. JPA then rightfully shouts if you try to call
object.save()
What makes this incredibly difficult to spot is, that
object.organizationalCell.toString()
will actually write out "null".
The solution:
ModelObject object = form.get();
if(object.organizationalCell.id == null) object.organizationalCell = null;
object.save();
Upvotes: 1
Reputation: 4361
Instead of
@ManyToOne(cascade = CascadeType.MERGE)
public OrganizationalCellUnit organizationalCellUnit = null;
Use this
@ManyToOne(cascade = CascadeType.ALL)
public OrganizationalCellUnit organizationalCellUnit;
Upvotes: 0