Hi,
we’re migrating to Hibernate 6.2 from 5.6. There’s problem when we call query setParameter on polymorphic type in HQL.
The exact issue is when we call setParameter with a proxied entity and inside the HQL query “where” clause is referenced parent poylmorphic type. Then we get the QueryArgumentException.
This worked fine in version 5, but now there’s some kind of validation in setParameter method and it throws this exception. Is this a bug or how we should deal with this?
I mean we don’t want unproxy every entity that is used as a parameter, it should work without unproxying as it did before
See the snippet below with a inline comment inside testQuery test.
org.hibernate.query.QueryArgumentException: Argument [org.hibernate.orm.test.annotations.inheritance.ProxyTest$UserSiteImpl@20] of type [org.hibernate.orm.test.annotations.inheritance.ProxyTest$UserSiteImpl$HibernateProxy$pP2CT8sK] did not match parameter type [org.hibernate.orm.test.annotations.inheritance.ProxyTest$SiteImpl (n/a)]
@DomainModel(
annotatedClasses = {
ProxyTest.SiteImpl.class,
ProxyTest.UserSiteImpl.class,
ProxyTest.BarImpl.class,
ProxyTest.BarBarImpl.class,
}
)
@SessionFactory
public class ProxyTest {
private Long siteId;
@Test
public void testQuery(SessionFactoryScope scope) {
scope.inTransaction(session -> {
UserSite userSite = session.getReference(UserSiteImpl.class, siteId);
List<Bar> bars = session.createQuery("SELECT b FROM Bar b inner join b.site as site WHERE site = ?1")
.setParameter(1, userSite) // This call fails, it used to work in version 5
.list();
BarImpl newBar = (BarImpl) bars.get(0);
assertNotNull(newBar);
assertNotNull(newBar.getSite());
assertFalse(Hibernate.isInitialized(newBar.getSite()));
assertEquals(siteId, newBar.getSite().getId());
});
}
@BeforeEach
public void setupData(SessionFactoryScope scope) {
this.siteId = scope.fromTransaction(session -> {
UserSiteImpl userSite = new UserSiteImpl();
userSite.id = 1L;
session.persist(userSite);
BarImpl bar = new BarImpl();
bar.id = 1L;
bar.setSite(userSite);
bar.setDetails("Some details");
session.persist(bar);
session.flush();
assertNotNull(userSite.getId());
assertEquals(userSite.getId(), bar.getSite().getId());
return userSite.getId();
});
}
@AfterEach
public void cleanupData(SessionFactoryScope scope) {
scope.inTransaction(session -> {
session.delete(session.find(UserSiteImpl.class, siteId));
session.delete(session.find(BarImpl.class, siteId));
});
this.siteId = null;
}
public interface EntityWithId {
Long getId();
}
public interface Site extends EntityWithId {
}
public interface UserSite extends Site {
}
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TYPE", length = 20, discriminatorType = DiscriminatorType.STRING)
@Proxy(proxyClass = Site.class)
public static abstract class SiteImpl implements Site {
@Id
protected Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Site foo = (Site) o;
return id.equals(foo.getId());
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
@Entity
@DiscriminatorValue("USER_SITE")
@Proxy(proxyClass = UserSite.class)
public static class UserSiteImpl extends SiteImpl implements UserSite {
}
public interface Bar extends EntityWithId {
}
public interface SitedBar<S extends Site> extends Bar {
S getSite();
}
@MappedSuperclass
@Proxy(proxyClass = SitedBar.class)
public static abstract class BarBarImpl<T extends Site> implements SitedBar<T> {
@ManyToOne(fetch = FetchType.LAZY, targetEntity = SiteImpl.class)
@JoinColumn(name = "BAR_ID")
private Site site;
@Override
public T getSite() {
return (T) site;
}
public void setSite(T site) {
this.site = site;
}
}
@Entity(name = "Bar")
public static class BarImpl extends BarBarImpl<UserSite> implements Bar {
@Id
private Long id;
private String details;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BarImpl bar = (BarImpl) o;
return id.equals(bar.getId());
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
}