Cannot persist entity with newly created nested sub entities

Hello, I am in the process of evaluating Cuba platform for a rather small business application (CRM application, managing trainers, clients and seminars in a rather flexible way) that needs to be as user friendly as possible (which means as few clicks, keystrokes and page navigations as possible).
In order to achieve this, I often need to create nested entities on behalf of the user in one step on a single page, so he does not need to navigate between pages to create single entities that need to be linked later.

So when I try to create an entity “Participant”, that links to an entity “Person” (which also links to an entity “Address”) using a “Participant” master detail screen, creating new entities Address and Person in this process, at the moment, the Participant->Person->Address object graph ist persisted, an exception occurrs:

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

I know, that probem was reported by other users already, but they worked with a previous 6.x cuba framework, while I am using 7.0.5. I cannot find recent relevant documentation how to solve this problem.
I attached corresponding screen code and XML. Hint: Teilnehmer = Participant

Any help will be greatly appreciated.

Dietmar

TeilnehmerBrowse.java (6.2 KB)
teilnehmer-browse.xml (5.4 KB)

Hi,

Can you share the relevant part of the domain model? The error is related to how the entites are connected.

It would be best if you create an example app simple as possible to see the error. This will skyrocket your chances to a proper answer very quickly :wink:

Bye
Mario

Thank you Mario,

you are right, there was indeed some problem with my domain model. I managed to correct that issue by adding the property cascade = CascadeType.PERSIST to the corresponding annotation, i.e.

@OneToOne(fetch = FetchType.LAZY, mappedBy = "", cascade = CascadeType.PERSIST)
@JoinColumn(name = "ADRESSE_ID")
protected Address adresse;

where adresse is my navigation property to the related Address entity within an outer Person entity.

Of course, I still don’t know, if this is the best way to resolve this issue or whether there are alternatives that might be better under certain circumstances. Older posts mentioned adding newly created entities to the datacontext, commitcontext or using nested datacollections, which I was not able to implement properly.
Would these options still be viable?

Address.java (1.6 KB)
Person.java (1.8 KB)
Teilnehmer.java (1.1 KB)

This error usually occurs when you create entity A, set it as attribute of entity B, and save only entity B. CascadeType.PERSIST solves the issue on the ORM level, but it’s not recommended in CUBA as sometimes leads to unexpected behavior. Better make sure entity A is saved too. Just create it via DataContext: dataContext.create(A.class);, then DataContext will commit it together with all changed entities of the screen.

2 Likes

Hi Konstantin.

I have the same issue, I need to persist entities (in cascade) programmatically from a service and I get the Exception:

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

For explanation, I create and attach a test project:

persistCascadeProject.zip (428.7 KB)

  • The Cuba version is 7.06.

  • The sample model are three classes in composition like this:
    composition

  • Have a service in middleware named PersistDataServiceBean, that have a method for persist test data on Entities A, B and C. For call it, I create a screen named “PersisitDataTestScreen” with a button.

Please can u tell me how can I do the persistence in cascade like JPA without the annotation cascade = CascadeType.PERSIST?

Thank you for your attention
Greetings,

Hi @rrdibernardo

Please can u tell me how can I do the persistence in cascade like JPA without the annotation cascade = CascadeType.PERSIST ?

It’s as simple as passing all created entities to the commit() method:

dataManager.commit(entityA, entityB1, entityB2, entityB3, entityC11, entityC12, entityC21);

It can also be done using CommitContext class:

        CommitContext cc = new CommitContext();

        EntityA entityA = dataManager.create(EntityA.class);
        entityA.setName("ENTITY A1");
        cc.addInstanceToCommit(entityA);

        EntityB entityB1 = dataManager.create(EntityB.class);
        entityB1.setNumber(1);
        entityB1.setEntityA(entityA);
        cc.addInstanceToCommit(entityB1);
        
        // ...
        dataManager.commit(cc);

Regards,
Konstantin

Thanks, I solved my problem yesterday.

In function of your sample code, my mistake was that I adding the new EntityB object to the bidirectional relationship attribute of EntityA (bEntities).

@Composition
@OnDelete(DeletePolicy.CASCADE)
@OneToMany(mappedBy = “entityA”)
protected List<EntityB> bEntities;
   CommitContext cc = new CommitContext();

    EntityA entityA = dataManager.create(EntityA.class);
    entityA.setName("ENTITY A1");
    cc.addInstanceToCommit(entityA);

    EntityB entityB1 = dataManager.create(EntityB.class);
    entityB1.setNumber(1);
    entityB1.setEntityA(entityA);
    cc.addInstanceToCommit(entityB1);

    // THE MISTAKE.
    // THIS THROW THE EXCEPTION: IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST
    entityA.getBEntities().add(entityB1);

    // ...
    dataManager.commit(cc);

Just with “entityB1.setEntityA(entityA)” and committing both entities, it works.

Regards