Support MULTISET fetch strategy for @ElementCollection
FetchStrategy.MULTISET is seemingly not supported for @ElementCollection of Basic or Embeddable types.
Reproducer for Basic type:
Expand
Database schema (Postgres):
create table users (
id bigint
);
create table roles (
user_id bigint,
role text
);
insert into users (id) values (1);
insert into roles (user_id, role) values (1, 'test');
Entities and views:
@Entity
@Table(name = "users")
@Data
public class User {
@Id
Long id;
@ElementCollection
@CollectionTable(
name = "roles",
joinColumns = @JoinColumn(name = "user_id")
)
@Column(name = "role")
Set<String> roles;
}
@EntityView(User.class)
public interface UserView {
@IdMapping
Long getId();
@Mapping(fetch = FetchStrategy.MULTISET)
Set<String> getRoles();
}
When trying to fetch all UserView records, an exception is thrown:
Expand
Exception in thread "main" java.lang.RuntimeException: Could not invoke the proxy constructor 'public org.example.UserViewImpl(org.example.UserViewImpl,int,java.lang.Object[])' with the given tuple: [1, test] with the types: [java.lang.Long, java.lang.String]
at com.blazebit.persistence.view.impl.proxy.TupleConstructorReflectionInstantiator.newInstance(TupleConstructorReflectionInstantiator.java:81)
at com.blazebit.persistence.view.impl.objectbuilder.ViewTypeObjectBuilder.build(ViewTypeObjectBuilder.java:69)
at com.blazebit.persistence.impl.query.ObjectBuilderTypedQuery.getResultList(ObjectBuilderTypedQuery.java:60)
at com.blazebit.persistence.impl.AbstractQueryBuilder.getResultList(AbstractQueryBuilder.java:47)
...
Caused by: java.lang.reflect.InvocationTargetException
...
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at com.blazebit.persistence.view.impl.proxy.TupleConstructorReflectionInstantiator.newInstance(TupleConstructorReflectionInstantiator.java:68)
... 7 more
Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class java.util.Set (java.lang.String and java.util.Set are in module java.base of loader 'bootstrap')
at org.example.UserViewImpl.<init>(UserViewImpl.java:45)
... 13 more
Generated SQL query:
select u1_0.id,r1_0.role from users u1_0 left join roles r1_0 on u1_0.id=r1_0.user_id
Notes:
- With default JOIN fetch strategy everything works fine.
- If
rolesare converted to an@Embeddabletype with the only column, another exception is thrown:Using the MULTISET fetch strategy is not allowed with entity types. MULTISET at the attribute roles[org.example.UserView.getRoles] is not allowed!. I also tried to apply recommendation https://persistence.blazebit.com/documentation/1.6/entity-view/manual/en_US/#type-support-for-multiset-fetching but it resolves only one of errors, but not the mentioned one.
There is indeed currently no test for multiset fetching of basic collections, so I assume this must be a bug. Thanks for the report. Managed types (entity, embeddable) are not supported on purpose. The recommendation is that you also create an entity view for the embeddable type and use that instead of the embeddable.
I also tried to apply recommendation https://persistence.blazebit.com/documentation/1.6/entity-view/manual/en_US/#type-support-for-multiset-fetching but it resolves only one of errors, but not the mentioned one.
This is just for basic (i.e. single column) types, not for composite types like embeddables.