Thank you for the test project.
The problem here is twofold.
First, you cannot rely on lazy loading on screens with nested containers. It’s because nested instances loaded lazily will bypass DataContext and won’t be tracked for changes. So a fetch plan including nested collection is required.
Second, thanks to your use case, I discovered an issue with Kotlin entities and lazy loading of collections:
opened 08:48AM - 17 Feb 22 UTC
type: bug
Create two entities (notice initialized `ParentEntity.children` collection):
… ```java
@JmixEntity
@Table(name = "PARENT_ENTITY")
@Entity
public class ParentEntity {
@JmixGeneratedValue
@Column(name = "ID", nullable = false)
@Id
private UUID id;
@InstanceName
@Column(name = "NAME")
private String name;
@Composition
@OneToMany(mappedBy = "parentEntity")
private List<ChildEntity> children = new ArrayList<>(); // field initializer
// getters and setters
}
```
```java
@JmixEntity
@Table(name = "CHILD_ENTITY")
@Entity
public class ChildEntity {
@JmixGeneratedValue
@Column(name = "ID", nullable = false)
@Id
private UUID id;
@Column(name = "CHILDNAME")
private String childname;
@JoinColumn(name = "PARENT_ENTITY_ID", nullable = false)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private ParentEntity parentEntity;
// getters and setters
}
```
Write a test:
```java
@Test
void testJavaEntities() {
ParentEntity parent = dataManager.create(ParentEntity.class);
parent.setName("p1");
ChildEntity child = dataManager.create(ChildEntity.class);
child.setChildname("c1");
child.setParentEntity(parent);
dataManager.save(parent, child);
// here the collection is loaded eagerly for some reason
ParentEntity loadedParent = dataManager.load(Id.of(parent)).one();
System.out.println(">>>>>>>>>>> loaded parent");
List<ChildEntity> children = loadedParent.getChildren();
System.out.println(">>>>>>>>>>> get children: " + children);
System.out.println(">>>>>>>>>>> get children[0]: " + children.get(0));
// here you get UnfetchedAttribute exception
System.out.println(">>>>>>>>>>> get children[0].parent: " + children.get(0).getParentEntity());
}
```
The problem is relevant for Kotlin entities where Studio generates a non-null property for collections:
```
@Composition
@OneToMany(mappedBy = "parentEntity")
var children: MutableList<ChildEntity> = mutableListOf()
```
It causes the empty back reference to Parent. If you change the field declaration to nullable, the lazy loading will work (but the first problem will prevent changes to be saved automatically):
@Composition
@OneToMany(mappedBy = "parentEntity")
var children: MutableList<ChildEntity>? = null