la propiedad no nula hace referencia a un valor nulo o transitorio

81

Enfrentando problemas para salvar el objeto padre / hijo con hibernación. Cualquier idea sería muy apreciada.

org.hibernate.PropertyValueException: not-null property references a null or transient value: example.forms.InvoiceItem.invoice
    at org.hibernate.engine.Nullability.checkNullability(Nullability.java:100)
        .... (truncated)

mapeo de hibernación:

<hibernate-mapping package="example.forms">
    <class name="Invoice" table="Invoices">
        <id name="id" type="long">
            <generator class="native" />
        </id>
        <property name="invDate" type="timestamp" />
        <property name="customerId" type="int" />
        <set cascade="all" inverse="true" lazy="true" name="items" order-by="id">
            <key column="invoiceId" />
            <one-to-many class="InvoiceItem" />
        </set>
    </class>
    <class name="InvoiceItem" table="InvoiceItems">
        <id column="id" name="itemId" type="long">
            <generator class="native" />
        </id>
        <property name="productId" type="long" />
        <property name="packname" type="string" />
        <property name="quantity" type="int" />
        <property name="price" type="double" />
        <many-to-one class="example.forms.Invoice" column="invoiceId" name="invoice" not-null="true" />
    </class>
</hibernate-mapping>

InvoiceManager.java

class InvoiceManager {

    public Long save(Invoice theInvoice) throws RemoteException {
        Session session = HbmUtils.getSessionFactory().getCurrentSession();
        Transaction tx = null;
        Long id = null;
        try {
            tx = session.beginTransaction();
            session.persist(theInvoice);
            tx.commit();
            id = theInvoice.getId();
        } catch (RuntimeException e) {
            if (tx != null)
                tx.rollback();
            e.printStackTrace();
            throw new RemoteException("Invoice could not be saved");
        } finally {
            if (session.isOpen())
                session.close();
        }
        return id;
    }
}

Invoice.java

public class Invoice implements java.io.Serializable {
    private Long id;
    private Date invDate;
    private int customerId;
    private Set<InvoiceItem> items;

    public Long getId() {
        return id;
    }
    public Date getInvDate() {
        return invDate;
    }
    public int getCustomerId() {
        return customerId;
    }
    public Set<InvoiceItem> getItems() {
        return items;
    }
    void setId(Long id) {
        this.id = id;
    }
    void setInvDate(Date invDate) {
        this.invDate = invDate;
    }
    void setCustomerId(int customerId) {
        this.customerId = customerId;
    }
    void setItems(Set<InvoiceItem> items) {
        this.items = items;
    }
}

InvoiceItem.java

public class InvoiceItem implements java.io.Serializable {
    private Long itemId;
    private long productId;
    private String packname;
    private int quantity;
    private double price;
    private Invoice invoice;

    public Long getItemId() {
        return itemId;
    }
    public long getProductId() {
        return productId;
    }
    public String getPackname() {
        return packname;
    }
    public int getQuantity() {
        return quantity;
    }
    public double getPrice() {
        return price;
    }
    public Invoice getInvoice() {
        return invoice;
    }
    void setItemId(Long itemId) {
        this.itemId = itemId;
    }
    void setProductId(long productId) {
        this.productId = productId;
    }
    void setPackname(String packname) {
        this.packname = packname;
    }
    void setQuantity(int quantity) {
        this.quantity = quantity;
    }
    void setPrice(double price) {
        this.price = price;
    }
    void setInvoice(Invoice invoice) {
        this.invoice = invoice;
    }
}
WSK
fuente

Respuestas:

47

Cada InvoiceItemdebe tener una Invoiceunida a ella debido a la not-null="true"en el que muchos-a-uno de mapeo.

Entonces, la idea básica es que necesita configurar esa relación explícita en el código. Hay muchas formas de hacerlo. En tu clase veo un setItemsmétodo. NO veo un addInvoiceItemmétodo. Cuando configura elementos, debe recorrer el conjunto y llamar item.setInvoice(this)a todos los elementos. Si implementa un addItemmétodo, debe hacer lo mismo. O necesita configurar la Factura de todos los miembros de InvoiceItemla colección.

hvgotcodes
fuente
80

para los seguidores, este mensaje de error también puede significar "lo tiene haciendo referencia a un objeto extraño que aún no se ha guardado en la base de datos" (aunque esté allí y no sea nulo).

Rogerdpack
fuente
1
¿Y cómo puedo solucionar esto? Ejemplo: tengo Entity_A con una columna Entity_B, y en Entity_B tengo una columna Entity_A la relación es @OneToMany de A a B y cuando trato de actualizar Entity_A luego me da esta excepción, ¿cómo podría actualizar Entity_A?
FAndrew
@FAndrew ¿guardar Entity_B primero?
rogerdpack
3
y si tengo, por ejemplo, 100 Entity_B, busco todas las Entity_B editadas y si se editó, las actualizo. ¿No sería mejor si actualizo Entity_A?
FAndrew
6

Esto podría ser tan simple como:

@Column(name = "Some_Column", nullable = false)

pero mientras persiste, el valor de "Some_Column" es nulo, incluso si "Some_Column" puede no ser una clave primaria o externa.

Sandeep Jindal
fuente
2

Verifique los valores no guardados para su clave principal / ID de objeto en sus archivos hbm. Si ha automatizado la creación de ID mediante el marco de hibernación y está configurando la ID en algún lugar, arrojará este error. De forma predeterminada, el valor no guardado es 0, por lo que si establece la ID en 0, verá este error.

Rohitdev
fuente
0

Recibí el mismo error, pero lo resolví finalmente, en realidad no estaba configurando la Entidad del objeto que ya está guardada en la otra entidad y, por lo tanto, el valor del Objeto que estaba obteniendo para la clave foránea era nulo.

Pratswinz
fuente
0

Resolví eliminando la propiedad @Basic (opcional = falso) o simplemente actualicé boolean @Basic (opcional = verdadero)

Shahid Hussain Abbasi
fuente
-10

Haga que esa variable sea transitoria. Su problema se resolverá.

@Column(name="emp_name", nullable=false, length=30)
    private transient String empName;
manjunath
fuente
3
Estás diciendo acerca de resolver el error y no resolver el problema.
Karthik R