JPA-Verbundschlüssel mit ManyToOne, der org.hibernate.PropertyAccessException abruft: Feldwert konnte durch Reflection-Setter von nicht festgelegt werden

Ich habe einen zusammengesetzten SchlüsselContractServiceLocationPK aus drei Ausweisen gemacht (contractId, locationId, serviceId) vom Typ long in einer einbettbaren Klasse. Die Klasse, die diesen zusammengesetzten Schlüssel verwendet,ContractServiceLocationordnet diese IDs mit@MapsId Anmerkungen zu ihren Objekten. So sieht es aus (entfernte Setter / Getter und irrelevante Eigenschaften):

Vertrag

@Entity
@Table(name = "Contract")
public class Contract implements Serializable {

    public Contract() {
    }

    @Id
    @GeneratedValue
    private long id;
    @OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch= FetchType.EAGER)
    Collection<ContractServiceLocation> contractServiceLocation;
}

ContractServiceLocationPK

@Embeddable
public class ContractServiceLocationPK implements Serializable {

    private long contractId;
    private long locationId;
    private long serviceId;
}

ContractServiceLocation

@Entity
@Table(name="Contract_Service_Location")
public class ContractServiceLocation implements Serializable {

    @EmbeddedId
    ContractServiceLocationPK id;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("contractId")
    Contract contract;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("locationId")
    Location location;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("serviceId")
    Service service;    

    BigDecimal price;
}

Wenn ich versuche, ein Objekt vom Typ ContractServiceLocation in irgendeiner Weise (direkt oder vertraglich) beizubehalten, erhalte ich:

Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of com.test.model.ContractServiceLocationPK.contractId
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
    at com.test.MainTest.main(MainTest.java:139)
Caused by: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of com.test.model.ContractServiceLocationPK.contractId
    at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:134)
    at org.hibernate.mapping.Component$ValueGenerationPlan.execute(Component.java:441)
    at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:121)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
    ... 1 more
Caused by: java.lang.NullPointerException
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(Unknown Source)
    at sun.reflect.UnsafeLongFieldAccessorImpl.set(Unknown Source)
    at java.lang.reflect.Field.set(Unknown Source)
    at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:122)
    ... 12 more

Ich gehe davon aus, dass JPA / Hibernate ein Vertragsobjekt anstelle einer langen Variablen erwartet, aber wenn ich die Variablen in embeddable von long auf ihren Typ ändere, erhalte ichThe type of the ID mapped by the relationship 'contract' does not agree with the primary key class of the target entity.. Wenn ich versuche, id class anstelle von embeddable zu verwenden, dannmappedby In der OneToMany-Zuordnung von Contract erhalte ichIn attribute 'contractServiceLocation', the "mapped by" attribute 'contract' has an invalid mapping type for this relationship.. Was soll ich tun, um einen zusammengesetzten Schlüssel mit mehreren zu erstellen?ManyToOne Zuordnungen?

BEARBEITEN: Ein Snippet wurde hinzugefügt, in dem ich versuche, die Elemente beizubehalten:

    Service service = new Service();
    // Set all service properties       
    Contract contract = new Contract();
    // Set all contract properties
    Location location = new Location();
    // Set all location properties
    ContractServiceLocation csl = new ContractServiceLocation();
    csl.setContract(contract);
    csl.setLocation(location);
    csl.setService(service);
    Collection<ContractServiceLocation> cslItems = new ArrayList<>();
    cslItems.add(csl);

    em.getTransaction().begin();
    em.persist(location);
    em.persist(service);
    em.persist(csl);
    em.persist(contract);
    em.getTransaction().commit();

Der Grund, warum es so aussieht, anstatt in einem DAO zu sein, ist, dass ich die Datenbank erst generiere und die Elemente teste, bevor ich mit der Entwicklung des Restes der App fortfahre.

EDIT 2: Ich habe meine Modelle umgeschrieben und jetzt scheint alles zu funktionieren, außer in Eclipse erhalte ich einen dauerhaften Fehler. So sehen die Dinge aktuell aus:

Vertrag - keine Änderung (außer das eifrige Laden wurde entfernt)

ContractServiceLocationPK - Ist jetzt eine ID-Klasse

public class ContractServiceLocationPK implements Serializable {

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)      
    @JoinColumn(name = "contract_id")
    private Contract contract;
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)      
    @JoinColumn(name = "location_id")
    private Location location;
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)      
    @JoinColumn(name = "service_id")
    private Service service;

    //getters and setters
    //overridden equals() and hashCode()
}

ContractServiceLocation

@Entity
@Table(name="Contract_Service_Location")
@IdClass(ContractServiceLocationPK.class)
public class ContractServiceLocation implements Serializable {

    @Id
    Contract contract;

    @Id
    Location location;

    @Id
    Service service;    

    BigDecimal price;
        //getters and setters
        //overridden equals() and hashCode()
}

Dies scheint vorerst korrekt zu funktionieren. Es wird ein zusammengesetzter Schlüssel erstellt und eine 1: 1-Beziehung zu allen zusammengesetzten Eigenschaften aufrechterhalten. Es gibt jedoch etwas Seltsames. In Vertragsfinsternis MarkenmappedBy auf der@OneToMany Anmerkung für dieContractServiceLocation Sammlung mit der FehlermeldungIn attribute 'contractServiceLocation', the "mapped by" attribute 'contract' has an invalid mapping type for this relationship.. Ich gehe davon aus, dass dies daran liegt, dass dieContract Eigenschaft definiert inContractServiceLocation hat keine@ManyToOne Anmerkung, aber das ist in der zusammengesetzten Klasse definiert. Stolperte ich über eine "nicht konforme JPA, aber mit Ruhezustand arbeitende" Falle oder was ist hier los?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage