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