JPA Составной ключ с ManyToOne, получающий org.hibernate.PropertyAccessException: не мог установить значение поля установщиком отражения

У меня есть составной ключContractServiceLocationPK сделан из трех идентификаторов (contractId, locationId, serviceId) типа long в встраиваемом классе. Класс, который использует этот составной ключ,ContractServiceLocation, сопоставляет эти идентификаторы, используя@MapsId аннотации к своим объектам. Вот как это выглядит (удалены сеттеры / геттеры и нерелевантные свойства):

контракт

@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;
}

При попытке сохранить объект типа ContractServiceLocation любым способом (напрямую или через контракт) я получаю:

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

Я предполагаю, что JPA / Hibernate ожидает объект Contract вместо длинной переменной, но если я изменю переменные в embeddable с long на их тип, то получуThe type of the ID mapped by the relationship 'contract' does not agree with the primary key class of the target entity., Если я попытаюсь использовать класс id вместо встраиваемого, тоmappedby в контракте OneToMany контракта я получаюIn attribute 'contractServiceLocation', the "mapped by" attribute 'contract' has an invalid mapping type for this relationship., Что я должен сделать, чтобы составной ключ с несколькимиManyToOne отображения?

РЕДАКТИРОВАТЬ: Добавлен фрагмент, где я пытаюсь сохранить элементы:

    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();

Причина, по которой это выглядит, а не в каком-то DAO, заключается в том, что я генерирую базу данных и сначала тестирую элементы, прежде чем приступить к разработке остальной части приложения.

РЕДАКТИРОВАТЬ 2: Я переписал свои модели, и теперь все, кажется, работает, за исключением Eclipse, я получаю постоянную ошибку. Вот как все выглядит в настоящее время:

Контракт - Без изменений (за исключением удаленной загрузки)

ContractServiceLocationPK - теперь класс идентификатора

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()
}

На данный момент это работает правильно. Он создает составной ключ и поддерживает отношение «многие к одному» со всеми составными свойствами. Однако есть что-то странное. В контракте знаки затменияmappedBy на@OneToMany аннотация дляContractServiceLocation сборник с сообщением об ошибкеIn attribute 'contractServiceLocation', the "mapped by" attribute 'contract' has an invalid mapping type for this relationship., Я предполагаю, что это потому, чтоContract свойство, определенное вContractServiceLocation не имеет@ManyToOne аннотации, но это определено в составном классе. Я наткнулся на «несовместимую JPA, но работаю с Hibernate» ловушкой или что здесь происходит?

Ответы на вопрос(2)

Ваш ответ на вопрос