jpa / hibernate @ManyToOne put null error:org.hibernate.TransientPropertyValueException:

时间:2014-12-04 11:41:02

标签: hibernate jpa persistence many-to-one

我的表单中有OrganizationalCell之类的决策选择字段:当我选择一个选项fe:OrganizationalCellUnit时,我必须使用实体OrganizationalCellUnit获取另一个输入,这只是强制性的在那个配置中。

当我选择其他值时,这个不再是强制性的(OrganizationalCellUnit)。

我有我想要坚持的实体:

@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;

我收到了一个错误:

Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: models.MedicalIncident.organizationalCellUnit -> models.OrganizationalCellUnit

在db中,这些字段允许nullabe值。

如何使此字段不是必需的,并使hibernate在db

中放置null值

--- ----更新 在将CascadeType更新为多个到一个关系之后,我有这个错误:

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]

---编辑已添加

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();
//  }


}

2 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,事实证明(至少在我的情况下)这是Play的错 - 我也可以看到你使用Play。

ModelObject object = form.get()

即使 organizationalCell 字段未从表单传递,Play实际上也会创建一个虚拟模型对象(在您的情况下为OrganizationalCellUnit类型)。所以object.organizationalCell不是 null 。如果你试图打电话,JPA会正确地喊叫

object.save()

让人难以置信的是,

object.organizationalCell.toString()

实际上会写出“null”。

解决方案:

ModelObject object = form.get();
if(object.organizationalCell.id == null) object.organizationalCell = null;

object.save();

答案 1 :(得分:0)

而不是

@ManyToOne(cascade = CascadeType.MERGE)
public OrganizationalCellUnit organizationalCellUnit = null;

使用此

@ManyToOne(cascade = CascadeType.ALL)
public OrganizationalCellUnit organizationalCellUnit;