During synchronization a new object was found through a relationship that was not marked cascade PERSIST

I have two section “fornitori” (suppliers) and “fatture fornitori” (invoices)

  • I can create an invoice in both section.

  • Invoice details is created initially by default with a list of “causali”

demo.rar (10.9 MB)

user: admin
password: admin

In first example (section “fornitori”) i have no error when i create an invoice.

Cattura1

Cattura2

Cattura3

Cattura4

In the second example (section “fatture fornitori”) when i creaete an invoice i have this error

IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST:

Cattura1B

Cattura2B

Cattura3B

Cattura4B

Cattura5B

I think that i create the detail incorrectly when i select “fornitore” (controller FornitoreFatturaEdit method copiaCausaliFornitore(item))

import javax.inject.Inject;
import javax.inject.Named;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class FornitoreFatturaEdit extends AbstractEditor<FornitoreFattura> {

    @Inject
    protected Messages messages;

    @Inject
    private DataManager dataManager;

    @Inject
    protected CollectionDatasource<Fornitore, UUID> fornitoriDs;

    @Named("fieldGroup.fornitore")
    protected LookupPickerField fornitoreField;

    @Override
    protected void initNewItem(FornitoreFattura item) {
        if (item.getFornitore() != null) {
            // fornitoreField.setVisible(false);
            fornitoreField.setEnabled(false);
            copiaCausaliFornitore(item);
        }
        fornitoriDs.addItemChangeListener(event -> {
            copiaCausaliFornitore(item);
        });


    }

    @Override
    protected boolean preCommit() {

        // controllo dataFattura < dataRegistrazione

        if (getItem().getDataFattura().after(getItem().getDataRegistrazione())) {
            String msg = messages.getMessage(getClass(), "dataFattVSDataReg");
            showNotification(msg, NotificationType.ERROR);
            return false;
        } else {
            return true;
        }
    }

    protected void copiaCausaliFornitore(FornitoreFattura item) {

        // esempio preso da data-manipulation

        LoadContext<FornitoreCausale> loadContext = LoadContext.create(FornitoreCausale.class)
                .setQuery(LoadContext.createQuery("select fc from congiunzione$FornitoreCausale fc where fc.fornitore.id = :fornitore")
                        .setParameter("fornitore", item.getFornitore().getId()))
                .setView("fornitoreCausale-view");

        List<FornitoreCausale> causaliPerFornitore = dataManager.loadList(loadContext);


        List<FornitoreFatturaDett> listFatturaDettaglioDaCausaliPerFornitore = new ArrayList<FornitoreFatturaDett>();

        for (int i = 0; i < causaliPerFornitore.size(); i++) {
            FornitoreFatturaDett ffd = new FornitoreFatturaDett();
            ffd.setFornitoreFattura(item); // per idFattura
            ffd.setTipoRiga(causaliPerFornitore.get(i).getTipoRiga()); // TipoRiga
            ffd.setCodiceConto(causaliPerFornitore.get(i).getCodiceConto()); // CodiceConto
            ffd.setImportoRiga(new BigDecimal(0.0)); // ImportoRiga
            ffd.setImportoIva(new BigDecimal(0.0)); // ImportoIva
            ffd.setAliqIva(causaliPerFornitore.get(i).getAliqIva()); // AlquotaIva
            ffd.setArtIva(causaliPerFornitore.get(i).getArtIva()); // ArticoloIva

            listFatturaDettaglioDaCausaliPerFornitore.add(ffd);

        }

        item.setLineaDettaglio(listFatturaDettaglioDaCausaliPerFornitore);
    }

}

hi,

the problem is that in the case of two levels of nesting, you have to manually add a nested datasource for the second level of nesting in the highest edit screen (fornitori in your case).

You can read about it here in the docs:
https://doc.cuba-platform.com/manual-6.8/composition_deep_recipe.html

terminal-edit.xml - the terminal edit screen XML descriptor contains a nested datasource and a corresponding table for the meetingPoints collection.

Or I actually had the very same problem when having this exact example in the ordermanagement video series. You can find the solution here: 05 - CUBA ordermanagement - hide customer selection in order screen - YouTube

Bye
Mario

Hi, my example “demo.rar” is based precisely on your excellent videos.

I think I’m wrong approaching how to fill the list with a method “copiaCausaliFornitore(item);”

fornitoriDs.addItemChangeListener(event -> {
        copiaCausaliFornitore(item);
    });

My problem is not when I create the detail list using the “create detail” button (in this case work correctly), the problem is when I automatically create the list when i change the LookupPickerField FORNITORI (image 3, second example) with the method “copiaCausaliFornitore(item)”; in the constructor “FornitoreFatturaEdit” .

datasource is correct and work perfectly if i create list by hand without automatic method copiaCausaliFornitore(item).

<dsContext>
    <datasource id="fornitoreDs"
                class="com.entity.Fornitore"
                view="fornitore-view">
        <collectionDatasource id="causaliDs"
                              property="causali"/>
        <collectionDatasource id="fattureDs"
                              property="fatture">
            <collectionDatasource id="lineaDettaglioDs"
                                  property="lineaDettaglio"/>
        </collectionDatasource>
    </datasource>
    <collectionDatasource id="logDs"
                          class="com.haulmont.cuba.security.entity.EntityLogItem"
                          view="logView">
        <query>
            <![CDATA[select i from sec$EntityLog i
            where i.entityRef.entityId = :ds$fornitoreDs order by i.eventTs desc]]>
        </query>
        <collectionDatasource id="logAttrDs"
                              property="attributes"/>
    </collectionDatasource>
    
</dsContext>

I solved my problem, I forgot to register the list in the DsContext :relaxed:

for (int i = 0; i < causaliPerFornitore.size(); i++) {
    //FornitoreFatturaDett ffd = new FornitoreFatturaDett();
    final FornitoreFatturaDett ffd = metadata.create(FornitoreFatturaDett.class);
    ....
    ffd.setXXX(causaliPerFornitore.get(i).getTipoRiga()); 
    .....

    listFatturaDettaglioDaCausaliPerFornitore.add(ffd);

    getDsContext().addBeforeCommitListener(context -> {
        context.getCommitInstances().add(ffd);
    });

}
1 Like