ManyToMany relationship to self with composite key with Spring-Repository

27 Views Asked by At

I have a composite key Resource_PK.class
I added it to the parent class Resource.class of my objects.

@NoArgsConstructor
@AllArgsConstructor
@ToString
@Getter
@Setter
@Embeddable
public class Resource_PK implements Serializable {

    private UUID id;

    private UUID partitionId;

    @Override
    public boolean equals(Object o) {
        if ( this == o ) {
            return true;
        }
        if ( o == null || getClass() != o.getClass() ) {
            return false;
        }
        Resource_PK pk = (Resource_PK) o;
        return Objects.equals( id, pk.partitionId ) &&
                Objects.equals( id, pk.partitionId );
    }

    @Override
    public int hashCode() {
        return Objects.hash( id, partitionId );
    }
}

@IdClass( Resource_PK.class)
@Getter
@Setter
public class Resource implements Serializable {
    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(name = "UUID",
            strategy = "de.si.dynamobffdatasetup.tools.UUIDGenerator")
    private UUID id;

    // partitions are NOT generated, they are set
    // they are part of the key, for performance reasons
    @Id
    private UUID partitionId;

I want to define a ManyToMany relationship from Equipment.class to self.

Equipment * -feeds-> * Equipment

@Entity
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Getter
@Setter
@DiscriminatorValue("3")
public class Equipment extends Resource {

    @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    private EquipmentType equipmentType;


    @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @JoinColumns({
            @JoinColumn(
                    name = "isPartOfParent_id",
                    referencedColumnName = "id"),
            @JoinColumn(
                    name = "isPartOfParent_partitionId",
                    referencedColumnName = "partitionId")
    })
    private Equipment isPartOfParent;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name="FeedsRel",
            joinColumns={
                    @JoinColumn(
                            name = "feedsrel_id",
                            referencedColumnName = "id"),
                    @JoinColumn(
                            name = "feedsrel_partitionId",
                            referencedColumnName = "partitionId")
            })
    private Set<Equipment> feeds = new HashSet<Equipment>();


    @ManyToMany( cascade = CascadeType.ALL, mappedBy="feeds", fetch = FetchType.EAGER)
    @Fetch(FetchMode.SUBSELECT)
    private Set<Equipment> fedBy = new HashSet<Equipment>();

So I find 2 equipments, set their relationship, save.

        // wire some equipment via feeds in a random partition
        final Partition partition = d.randomPartition();

        // find 2 equipments
        Set<Equipment> eqs = equipmentRepository.getRandom(partition.getId(), 2);
        Iterator<Equipment> iterator = eqs.iterator();
        Equipment e1 = iterator.next();
        Equipment e2 = iterator.next();

        // add them to each other explicitely
        e1.getFeeds().add(e2);
        e2.getFedBy().add(e1);


        equipmentRepository.saveAll(Arrays.asList(e1, e2));

But my problem is, that I always get an error about a duplicate composite key of e1 when I try to save:

Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "equipment_pkey"
  Detail: Key (id, partition_id)=(1e35ce1b-b2a4-49ff-b0ea-f8d66c76b16f, 424328b0-7953-48a9-9df9-7afd86600da8) already exists.
    at app//org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2675)
    at app//org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2365)
    at app//org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:355)
    at app//org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:490)
    at app//org.postgresql.jdbc.PgStatement.execute(PgStatement.java:408)
    at app//org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:167)
    at app//org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:135)
    at app//com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
    at app//com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
    at app//org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)

enter image description here

Question: How can I tell JPA and Spring, that this is an existing entity I save? So that it doesnt try to save the entity as new?

0

There are 0 best solutions below