@DependsOnProperties on field-based @Transient @JmixProperty erases the dependent JPA column during save when additional datastores are present

Environment

- Jmix version: 3.0.1
- Java: 21

Description

This is a variant of the issue fixed in #3700 (https://github.com/jmix-framework/jmix/issues/3700) (milestone 2.3.4). The fix in #3700 only excludes method-based properties from writeCrossDataStoreReferences. However, field-based
 @Transient @JmixProperty properties with @DependsOnProperties are still affected.

Entity setup

@JmixEntity
@Entity(name = "MainEntity")
public class MainEntity {

    @Id
    private UUID id;

    // JPA persistent column — stores the foreign key to the external datastore
    @Column(name = "EXTERNAL_REF_NAME")
    private String externalRefName;

    // Transient cross-datastore reference — resolved automatically on load
    @Transient
    @JmixProperty
    @DependsOnProperties("externalRefName")
    private ExternalEntity externalRef;
}

ExternalEntity is a DTO entity (@JmixEntity(annotatedPropertiesOnly = true)) belonging to an additional datastore configured via jmix.core.additional-stores.

Steps to reproduce

1. Create or load a MainEntity instance with externalRefName = "some-value"
2. Save the entity via dataContext.save() or dataManager.save()
3. Observe the SQL INSERT/UPDATE: EXTERNAL_REF_NAME is NULL

Expected result

EXTERNAL_REF_NAME should retain its value ("some-value") in the SQL statement.

Actual result

UnconstrainedDataManagerImpl#writeCrossDataStoreReferences detects the @DependsOnProperties("externalRefName") annotation on the transient field externalRef. Since ExternalEntity belongs to a different datastore, it invokes:

EntityValues.setValue(entity, "externalRefName", null);

This erases the JPA column value before EclipseLink generates the SQL.

Root cause analysis

In writeCrossDataStoreReferences (Jmix 3.0.1), the fix for #3700 added:

if (metadataTools.isMethodBased(property)) {
    continue; // skip method-based properties
}

But field-based @Transient @JmixProperty properties are not method-based, so they are still processed by the cross-datastore reference writer, which nullifies the @DependsOnProperties columns.

Proposed fix

Extend the skip condition to also exclude transient field-based properties that are not JPA-managed:

if (metadataTools.isMethodBased(property) || !metadataTools.isJpa(property)) {
    continue;
}

Or alternatively, only process properties that are actually persisted in the entity's own datastore.

Workaround

Use a combination of @EntityListeners + EntitySavingEvent + ThreadLocal to save the column values before writeCrossDataStoreReferences erases them, and restore them in a @PrePersist/@PreUpdate JPA callback.

Related issues

- #3700 (https://github.com/jmix-framework/jmix/issues/3700) — Fixed for method-based properties only (milestone 2.3.4)
- #3963 (https://github.com/jmix-framework/jmix/issues/3963) — Cross-datastore reference cleared with _base fetch plan

Hi,

Thanks for reporting.
We will take a look.

Regards,
Ivan