Duplicate primary key violation

Hello,

I’ve got a problem that started recently in a Jmix 1.5.3 project where a few entities are attempting to save twice. I’ve been going over this and can’t find the cause. I’m trying to verify that I caused this issue (I’m 95% sure I did) and it isn’t a bug. I’m using Screenbuilders to create a collection entity object, but I haven’t had this issue before, and I’ve also removed the type attribute from the create action in attempt to make sure the default action isn’t firing twice. This occurs when attempting to edit a Survey entity to add a new SurveyQuestion entity.

    @Subscribe("answerOptionsTable.create")
    public void onAnswerOptionsTableCreate(final Action.ActionPerformedEvent event) {
        screenBuilders.editor(SurveyAnswerOption.class, this)
                .withScreenClass(SurveyAnswerOptionEdit.class)
                .newEntity()
                .withInitializer(answerOption -> {
                    answerOption.setSurveyQuestion(getEditedEntity());
                    answerOption.setDisplayOrder(answerOptionsDc.getItems().size() + 1);
                })
                .withAfterCloseListener(screenCloseEvent -> {
                    if (screenCloseEvent.closedWith(StandardOutcome.COMMIT)) {
                        answerOptionsDc.getMutableItems().add(screenCloseEvent.getSource().getEditedEntity());
                    }
                })
                .build()
                .show();
    }

I turned on SQL debugging in the application.properties file and it produces the following:

2023-08-17 10:30:35.289 DEBUG 18671 --- [nio-8080-exec-1] i.jmix.core.datastore.AbstractDataStore  : load: store=main, metaClass=Survey, id=1, fetchPlan=com.company.surveypoc.entity.Survey/
2023-08-17 10:30:53.032 DEBUG 18671 --- [nio-8080-exec-1] i.jmix.core.datastore.AbstractDataStore  : save: store=main, entities to save: [com.company.surveypoc.entity.SurveyQuestion-201 [new], com.company.surveypoc.entity.SurveyAnswerOption-201 [new]], entities to remove: []
2023-08-17 10:30:54.576 DEBUG 18671 --- [io-8080-exec-10] i.jmix.core.datastore.AbstractDataStore  : save: store=main, entities to save: [com.company.surveypoc.entity.SurveyQuestion-201 [new]], entities to remove: []
2023-08-17 10:30:54.587  WARN 18671 --- [io-8080-exec-10] eclipselink.logging.all                  : Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.9.6-jmix): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pk_survey_question"
  Detail: Key (id)=(201) already exists.
Error Code: 0
Call: INSERT INTO SURVEY_QUESTION (ID, ANSWER_TYPE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, DISPLAY_ORDER, INIT_REQUIRED, INIT_VISIBLE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, QUESTION_TEXT, UUID, VERSION, SURVEY_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
	bind => [201, Multiple Answer Multiple Choice, admin, 2023-08-17 10:30:54.577, null, null, 3, true, true, null, 2023-08-17 10:30:54.577, aaaa, fdfc5821-4910-3a4a-8ad5-2876d780a4ee, 1, 1]
Query: InsertObjectQuery(com.company.surveypoc.entity.SurveyQuestion-201 [new,managed])

Does this have to do with adding the new entity into the data container after screen close?

answerOptionsDc.getMutableItems().add(screenCloseEvent.getSource().getEditedEntity());

I was just trying to get the collection table to reload, and it seemed to work with a new Survey entity. The reason I used ScreenBuilders here is to set the displayOrder value. I tried using a ScreenConfigurer instead and just using the standard create action, but I received a class cast error.

If this is a programmer error, would you point me in the right direction?

The project, if needed:
surveyPOC.zip (136.4 KB)

Thank you,
Adam

I found that my screenConfigurer works as a way to set the screen’s field instead of using ScreenBuilders to pass the value I needed to initialize. After figuring out that I copy/pasted the screenConfigurer handler, which had the wrong entity type, it serves the purpose that I need. I’m still not 100% sure why it was attempting to create the entity twice when using ScreenBuilders, but all seems to be resolved now.

Sorry for the unnecessary post.

Adam

I would like to say that I also discovered this behavior. In my instance I have to use the ScreenBuilder, so any help would be appreciated.

For context:
I have a 3 level composition ABC. I have a browse screen for A. I select an instance of A, and use ScreenBuilders to create a new instance of B and open up B's editor. In B’s editor, I create a C. When I go to save B, it is trying to double insert B into the database.

My code(ish):

@JmixEntity
@Table(name = "A")
@Entity(name = "app_A")
open class A : StandardEntity() {
...
    @Composition
    @OnDelete(DeletePolicy.DENY)
    @OneToMany(mappedBy = "a")
    var bs: MutableList<B> = NotInstantiatedList()
...
}

@JmixEntity
@Table(name = "B")
@Entity(name = "app_B")
open class B : StandardEntity() {
...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "A_ID")
    var a: A? = null

    // Updated to add Composition
    @Composition
    @OneToMany(mappedBy = "b")
    var cs: List<C> = NotInstantiatedList()
...
}

@JmixEntity
@Table(name = "C")
@Entity(name = "app_C")
class C : StandardEntity() {
...
}

It was only while writing this comment that I realized my B → C relationship was not annotated with @Composition. Adding this fixes my problem. I wanted to still post this comment to guide people that run into the same problem.