blaze-persistence icon indicating copy to clipboard operation
blaze-persistence copied to clipboard

Support MULTISET fetch strategy for @ElementCollection

Open ilia1243 opened this issue 7 months ago • 1 comments

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 roles are converted to an @Embeddable type 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.

ilia1243 avatar May 09 '25 10:05 ilia1243

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.

beikov avatar Jun 27 '25 09:06 beikov