Many-to-Many Using a Composite Key

Hello!
I’m trying to implement a many to many relationship with an additional field. To do this, I followed this guide which explains to create an entity for the relationship with the additional field, and a new embeddable class for the composite key. Link to the guide → Baeldung article
The 2 entities I have to relate are named PatrolPlanning and Agente.
The entity PatrolPlanningAgente implements the relationship:

@Table(name = "M365_PATROL_PLANNING_AGENTE_LINK")
@ Entity(name = "m365_PatrolPlanningAgente")
public class PatrolPlanningAgente extends StandardEntity {
private static final long serialVersionUID = 6178168724214992450L;

@ EmbeddedId
PatrolPlanningAgentePK2 id;

@ ManyToOne
@ MapsId("agenteId")
@ JoinColumn(name = "AGENTE_ID", nullable = false)
protected Agente agente;

@ ManyToOne
@ MapsId("patrolPlanningId")
@ JoinColumn(name = "PATROL_PLANNING_ID", nullable = false)
protected PatrolPlanning patrolPlanning;

@ NotNull
@ Column(name = "PATROL_LEADER", nullable = false)
protected Boolean patrolLeader = false;
}

And this is the class I created for the composite primary key:

@ MetaClass(name = "m365_PatrolPlanningAgentePK2")
@ Embeddable
public class PatrolPlanningAgentePK2 extends EmbeddableEntity {
private static final long serialVersionUID = 1555130521418561940L;


@ Column(name = "AGENTE_ID")
private UUID patrolPlanningId;

@ Column(name = "PATROL_PLANNING_ID")
private UUID agenteId;

public PatrolPlanningAgentePK2(){}


public PatrolPlanningAgentePK2(UUID patrolPlanning, UUID agente) {
    this.patrolPlanningId = patrolPlanning;
    this.agenteId = agente;
}

public boolean equals(Object object) {
    if (object instanceof PatrolPlanningAgentePK2) {
        PatrolPlanningAgentePK2 pk = (PatrolPlanningAgentePK2)object;
        return this.patrolPlanningId == pk.patrolPlanningId && this.agenteId == pk.agenteId;
    } else {
        return false;
    }
}

public int hashCode() {
    return (int)(this.patrolPlanningId.hashCode() + this.agenteId.hashCode());
}

}

This seems to work, because now Cuba creates my DB correctly as I want it, but I have an exception when I try to run the application:

org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: java.lang.ClassCastException: class org.eclipse.persistence.mappings.AggregateObjectMapping cannot be cast to class org.eclipse.persistence.mappings.DirectToFieldMapping (org.eclipse.persistence.mappings.AggregateObjectMapping and org.eclipse.persistence.mappings.DirectToFieldMapping are in unnamed module of loader java.net.URLClassLoader @15eb5ee5)

What does this mean? May I missed something?
Thank you!

Dario

Hi,

Generally a many to many relationship with additional fields is just represented as a regular mapping entity.

Here in this CUBA guide there is a explanation and example for it: https://www.cuba-platform.com/guides/data-modelling-many-to-many-association

I hope this helps, Mario

Hi Mario,

ok thank you for this article!
The fact is that we want a primary key for the InsuranceMembership entity, in your example, that is a combination of the foreign keys, PET_ID and INSURANCE_COMPANY_ID, so that is impossible to create two InsuranceMembership with the same Pet and the same InsuranceCompany.
Maybe in this example this does not makes sense, but in my case it is necessary and I would like to know if it’s possible.

Thank you,
Dario

It is possible even in this example. You need to create a unique index on those two columns on the entity. Then the DB will restrict that combination.

In case you use soft delete from Cuba, you also need to put the deleteTs column in the index.

Bye
Mario