2 one-to-many compositions with same entity messes with Table content

Hi

I have an entity CarTransaction with 2 one-to-many compositions as list of CarDocument, one is buyerDocuments other is sellerDocuments.

These 2 lists are computed at entity level by another class CarTransactionCalculator when one property of the CarTransaction changes.

Managed to reproduce the issue in the sample project attached. If you create through editor a

CarTransaction it will properly compute 1 seller doc and 1 buyer doc.

image

Then save and reopen item, now sellerDocs table and buyerDocs tables display all documents.

image

If you look in database, there is no such duplicate, this is only in the screen.

Then by changing a letter in label field, docs are recalculated, the duplicates disappear.

I think this is related to the fact there are 2 compositions with same target entity class CarDocument in CarTransaction.

EDIT : with a bit of debugging I saw taht it happens at load time, the CarTransaction loaded is already messed up, so I think the issue is in the query/fetch. Assumption : a single join is made to load all docs but then they are not dispatched between the 2 properties sellerDocs and buyerDocs.

Regards
Michael

comp2.zip (80.1 KB)

I’m pretty sure the case is expected behavior.

Then by changing a letter in label field, docs are recalculated, the duplicates disappear.

Because it’s handled manually in CarTransactionCalculator.

they are not dispatched between the 2 properties sellerDocs and buyerDocs

The same entity is used for both fields, and there is no way to determine which entities should be used for some field.

I’d suggest you to use two different entities for your fields.

Regards

Hi @tsarev

Indeed, I reached the same conclusion.

The properties buyerDocs and sellerDocs have no existence in the the concrete model in database. So there is only one relationship with CarDocument at this level.

I fixed that by having a single property ‘documents’ and adding an enum defining the recipient seller/buyer for the association, within CarDocument.

Which leads me to another question, I created 2 following methods in CarTransaction:

    @MetaProperty
    public List<CarDocument> getBuyerDocuments() {
        return Collections.unmodifiableList(getDocuments().stream().filter(d->d.getRecipient() == BUYER).collect(Collectors.toList()));
    }
    @MetaProperty
    public List<CarDocument> getSellerDocuments() {
        return Collections.unmodifiableList(getDocuments().stream().filter(d->d.getRecipient() == SELLER).collect(Collectors.toList()));
    }

How can I map these 2 read-only properties to 2 tables ?

I tried the following, setting 2 property data container in order to bind them to tables, but it does not work, because metaproperties are read-only.

<instance id="carTransactionDc"
                  class="com.company.comp2.entity.CarTransaction"
                  view="carTransaction-view">
            <loader id="carTransactionDl"/>
            <collection id="sellerDocumentsDc" property="sellerDocuments"/>
            <collection id="buyerDocumentsDc" property="buyerDocuments"/>
        </instance>

Regards
Michael

Just save new documents manually and update corresponding documents property, that will trigger meta-properties update

Ok, but this will prevent canceling edition.

If a new document is added for the transaction, respective tables should be updated, but user still have the choice to cancel edition.

I guess I will have to create data containers and update them myself when related CarTransaction instance changes, like below.

        <collection id="sellerDocumentsDc"
                    class="com.company.svp.entity.CarDocument"
                    view="carDocument-view">
        </collection>
        <collection id="buyerDocumentsDc"
                    class="com.company.svp.entity.CarDocument"
                    view="carDocument-view">
        </collection>
    @Subscribe(id = "carTransactionDc", target = Target.DATA_CONTAINER)
    public void onCarTransactionDcItemChange(InstanceContainer.ItemChangeEvent<CarTransaction> event) {
        [...]
        // calculated containers
        sellerDocumentsDc.getMutableItems().clear();
        sellerDocumentsDc.getMutableItems().addAll(getEditedEntity().getSellerDocuments());
        buyerDocumentsDc.getMutableItems().clear();
        buyerDocumentsDc.getMutableItems().addAll(getEditedEntity().getBuyerDocuments());
    }

It does the job but if you think there is better, I’m open.

Regards
Michael

Anyway the case requires some custom solution, but there are can exist several ones, so it depends on business logic or / and any other requirements.