@OneToMany with interface type return variable (role column) @Any

Hello,

I have a collection that has a return variable that can be of multiple types and therefore uses a ROLE (or D-TYPE) column.

For this return variable I cannot use @ManyToOne because it does not allow the use of ROLE columns.
So I use an @ANY

Everything works except that the ROLE column (here ELEMENTDETRAVAIL_ROLE) is not updated during the persisterCollection.

Do you have any idea how to handle this case?

Thanking you.

public class Agent implements IElementDeTravail 
...
@OneToMany
@JoinColumn(name = "ELEMENTDETRAVAIL_ID")
private Set<Tache> taches = new HashSet<>();

public class Tache
....
@Any(metaDef = "IElementDeTravailMetaDef", metaColumn = @Column(name = "ELEMENTDETRAVAIL_ROLE"))
@JoinColumn(name = "ELEMENTDETRAVAIL_ID")
private IElementDeTravail elementDeTravail;

For information, we are migrating to hibernate 6.1.5 but I don’t think it changes much, except the @AnyValue and the metadef

22/12/2022 : small correction there was no mappedby which is not compatible with the @JoinColumn

Might be a bug. Please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(hibernate-test-case-templates/JPAUnitTestCase.java at main · hibernate/hibernate-test-case-templates · GitHub) that reproduces the issue.

I do this as soon as possible. Thanks very much.

In fact to be more precise the real problem is rather with the use of mappedBy (normal use).

And there it tells us the collection foreign key mapping has wrong number of column.

Logical because the primary key of Agent consists only of an ID column while the foreign key of two columns ID + ROLE

Caused by: org.hibernate.MappingException: collection foreign key mapping has wrong number of columns: org.hibernate.bugs.entity.Affaire.taches type: long
	at org.hibernate.mapping.Collection.validate(Collection.java:379)
	at org.hibernate.mapping.Set.validate(Set.java:51)
	at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:380)
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:301)
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:415)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1425)

I add the source code of the TU.

Do I still create a JIRA ticket?

package org.hibernate.bugs.entity;

import java.util.Set;
import jakarta.persistence.*;

@Entity
@DiscriminatorColumn
@DiscriminatorValue("affaire")
public class Affaire implements IElementDeTravail {

  @Id
  @GeneratedValue
  private Long id;

  @OneToMany(mappedBy = "elementDeTravail", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  private Set<Tache> taches;

  public void setId(final Long id) {
    this.id = id;
  }

  public Long getId() {
    return id;
  }

  public Set<Tache> getTaches() {
    return taches;
  }

  public void setTaches(final Set<Tache> taches) {
    this.taches = taches;
  }
}

package org.hibernate.bugs.entity;

import jakarta.persistence.*;
import org.hibernate.annotations.*;
import org.hibernate.annotations.JavaType;
import org.hibernate.type.descriptor.java.*;

@Entity
public class Tache {

  @Id
  @GeneratedValue
  private Long id;

  @Any
  @AnyDiscriminator(DiscriminatorType.STRING)
  @AnyDiscriminatorValue(discriminator = "affaire", entity = Affaire.class)
  @AnyKeyJavaClass(Long.class)
  @Column(name = "ELEMENTDETRAVAIL_ROLE")
  @JoinColumn(name = "ELEMENTDETRAVAIL_ID")
  private IElementDeTravail elementDeTravail;

  public void setId(final Long id) {
    this.id = id;
  }

  public Long getId() {
    return id;
  }

  public IElementDeTravail getElementDeTravail() {
    return elementDeTravail;
  }

  public void setElementDeTravail(final IElementDeTravail objetMaitre) {
    this.elementDeTravail = objetMaitre;
  }
}

package org.hibernate.bugs;

import java.util.Set;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

import org.hibernate.Session;
import org.hibernate.bugs.entity.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * This template demonstrates how to develop a test case for Hibernate ORM, using the Java Persistence API.
 */
public class JPAUnitTestCase {

 private EntityManagerFactory entityManagerFactory;

 @Before
 public void init() {
  entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
 }

 @After
 public void destroy() {
  entityManagerFactory.close();
 }

 // Entities are auto-discovered, so just add them anywhere on class-path
 // Add your tests, using standard JUnit.
 @Test
 public void hhh123Test() throws Exception {
  EntityManager entityManager = entityManagerFactory.createEntityManager();
  entityManager.getTransaction().begin();
  // Do stuff...

  Affaire affaire = new Affaire();
  final Set<Tache> taches = Set.of(new Tache(), new Tache());
  affaire.setTaches(taches);

  entityManager.persist(affaire);
  entityManager.flush();
  entityManager.clear();

// KO here
  final Affaire affaireReload = entityManager.unwrap(Session.class).byId(affaire.getClass()).load(affaire.getId());

  entityManager.getTransaction().commit();
  entityManager.close();

 }
}

You’re not the first one to ask for this. You can track this issue: [HHH-15722] - Hibernate JIRA

It’s actually the same issue.
I wait then, no need to recreate a JIRA ticket that would be duplicated.

Thanks to you