Trouble populating non-persistent entity attributes

Hi, forum followers and cuba support team.

When we’re trying to populate a non-persistent entity attribute with the listener BeforeDetachEntityListener the value is correctly assigned but the error “Cannot get unfetched attribute from detached object” on the entity-browser form appears although all attributes are included on the corresponding view. But, if the sentence @Listeners(“UbicacioEntityListener”) in Entity definition is commented, the entity-browser form doesn’t produce this error and, of course, the transient attribute doesn’t have any value.

We have checked that entity-browser’s view include all necessary attributes, but we don’t resolve the problem.

We would be very grateful if someone could help us.

Error message:

Class with transient ‘saldo’ attribute:

package com.company.magatzem.entity;

import com.haulmont.chile.core.annotations.MetaProperty;
import com.haulmont.chile.core.annotations.NamePattern;
import com.haulmont.cuba.core.entity.StandardEntity;
import com.haulmont.cuba.core.entity.annotation.*;
import com.haulmont.cuba.core.global.DeletePolicy;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

@PublishEntityChangedEvents
@NamePattern("%s|ubicacioId")
@Table(name = "MAGATZEM_UBICACIO")
@Entity(name = "magatzem_Ubicacio")
@Listeners("UbicacioEntityListener")
public class Ubicacio extends StandardEntity {
    private static final long serialVersionUID = -4212919895910187491L;

    @CaseConversion
    @Pattern(message = "{msg://magatzem_Ubicacio.ubicacioId.validation.Pattern}", regexp = "[A-Z]{1}[0-9]{2}[0-9]{2}")
    @NotBlank(message = "La ubicació no pot tenir espais en blanc")
    @NotEmpty(message = "{msg://magatzem_Ubicacio.ubicacioId.validation.NotEmpty}")
    @NotNull
    @Column(name = "UBICACIO_ID", nullable = false, length = 8)
    protected String ubicacioId;

    @OnDelete(DeletePolicy.DENY)
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "DARRER_MOVIMENT_ID")
    private MovimentUbicacio darrerMoviment;

    @Column(name = "COMENTARI")
    protected String comentari;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "MAGATZEM_ID")
    protected Magatzem magatzem;

    @OnDeleteInverse(DeletePolicy.DENY)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PARTIDA_ID")
    protected Partida partida;

    @Transient
    @MetaProperty(related = {"partida"})
    private Integer saldo;

    public Integer getSaldo() {
        return saldo;
    }

    public void setSaldo(Integer saldo) { this.saldo = saldo;}

    public MovimentUbicacio getDarrerMoviment() {
        return darrerMoviment;
    }

    public void setDarrerMoviment(MovimentUbicacio darrerMoviment) {
        this.darrerMoviment = darrerMoviment;
    }

    public Partida getPartida() {
        return partida;
    }

    public void setPartida(Partida partida) {
        this.partida = partida;
    }

    public String getComentari() {
        return comentari;
    }

    public void setComentari(String comentari) {
        this.comentari = comentari;
    }

    public Magatzem getMagatzem() {
        return magatzem;
    }

    public void setMagatzem(Magatzem magatzem) {
        this.magatzem = magatzem;
    }

    public String getUbicacioId() {
        return ubicacioId;
    }

    public void setUbicacioId(String ubicacioId) {
        this.ubicacioId = ubicacioId;
    }

}

EntityListener with BeforeDetachEntityListener:

package com.company.magatzem.listeners;

import com.company.magatzem.service.UbicacioService;
import org.springframework.stereotype.Component;
import com.haulmont.cuba.core.listener.*;
import javax.inject.Inject;
import com.haulmont.cuba.core.EntityManager;
import com.company.magatzem.entity.Ubicacio;

@Component("UbicacioEntityListener")
public class UbicacioEntityListener implements BeforeDetachEntityListener<Ubicacio> {
    @Inject
    private UbicacioService ubicacioService;

    @Override
    public void onBeforeDetach(Ubicacio ubicacio, EntityManager entityManager){
        ubicacio.setSaldo(ubicacioService.getSaldoUnitats(ubicacio, ubicacio.getPartida()));
    }
}

Entity-browser form that produces "“Cannot get unfetched attribute[comentari] from detached object” error:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
        xmlns:c="http://schemas.haulmont.com/cuba/screen/jpql_condition.xsd"
        caption="msg://browseCaption"
        focusComponent="ubicaciosTable"
        messagesPack="com.company.magatzem.web.screens.ubicacio">
    <data readOnly="true">
        <collection id="ubicaciosDc"
                    class="com.company.magatzem.entity.Ubicacio"
                    view="ubicacio-selector">
            <loader id="ubicaciosDl">
                <query>
                    <![CDATA[select e from magatzem_Ubicacio e]]>
                </query>
            </loader>
        </collection>
    </data>
    <dialogMode height="600"
                width="800"/>
    <layout expand="ubicaciosTable"
            spacing="true">
        <filter id="filter"
                applyTo="ubicaciosTable"
                dataLoader="ubicaciosDl">
            <properties include=".*"/>
        </filter>
        <groupTable id="ubicaciosTable"
                    width="100%"
                    dataContainer="ubicaciosDc">
            <actions>
                <action id="create" type="create"/>
                <action id="edit" type="edit"/>
                <action id="remove" type="remove"/>
            </actions>
            <columns>
                <column id="ubicacioId">
                    <formatter class="com.company.magatzem.web.UbicacioFormata"/>
                </column>
                <column id="comentari"/>
                <column id="magatzem"/>
                <column id="saldo"/>
            </columns>
            <rowsCount/>
            <buttonsPanel id="buttonsPanel"
                          alwaysVisible="true">
                <button id="createBtn" action="ubicaciosTable.create"/>
                <button id="editBtn" action="ubicaciosTable.edit"/>
                <button id="removeBtn" action="ubicaciosTable.remove"/>
            </buttonsPanel>
        </groupTable>
        <hbox id="lookupActions" spacing="true" visible="false">
            <button action="lookupSelectAction"/>
            <button action="lookupCancelAction"/>
        </hbox>
    </layout>
</window>

Affected view “ubicacio-selector”:

<view entity="magatzem_Ubicacio" name="ubicacio-selector" systemProperties="true">
        <property name="saldo"/>
        <property name="magatzem" view="_minimal" fetch="AUTO"/>
        <property name="partida" view="_minimal" fetch="AUTO"/>
        <property name="ubicacioId"/>
        <property name="comentari"/>
    </view>

Our development platform is:

  • CUBA Platform version: 7.2.19
  • CUBA Studio plugin version: 15.9-202
  • IntelliJ version: CUBA Studio 2020.2

Hi Xavier,

Perhaps the error occurs in your UbicacioService.
Maybe it reloads the entity with a different view?

1 Like

Thanks a lot, Konstantin.
You’re right!.
Although in UbicacioService use another entity to calculate the balance of units, the associated view didn’t load necessary attributes for entity ‘Ubicacio’ to be displayed on Ubicacio-entity-browser form.