Исключение гибернации с @MapsId, @EmbeddedId - PullRequest
7 голосов
/ 02 ноября 2011

У меня проблема с @MapsId аннотацией и @EmbeddedId. При запуске кода в Hibernate я получаю:

Причина: org.hibernate.PropertyAccessException: не удалось установить значение поля с помощью установки отражения com.test.entities.EmployeeId.serverId

Но давайте начнем с самого начала ... У меня есть составной первичный ключ для сущности Employee, который состоит из внешних ключей для двух других сущностей (Server и Website). Чтобы иметь чистый дизайн, я использую отношения сущностей в сущности Сотрудника, которые должны быть отражены в встраиваемом элементе EmployeeId. Пример довольно прост и выглядит следующим образом:

@Entity
public class Server implements Serializable {

    @Id
    @GeneratedValue
    private int id;

    private String url;

    public Server() {}

    public Server(String name) {
        this.url = name;
    }
}

@Entity
public class Website implements Serializable {

    @Id
    @GeneratedValue
    private int id;

    private String name;

    public Website() {}

    public Website(String name) {
        this.name = name;
    }
}

@Embeddable
public class EmployeeId implements Serializable {

    protected int websiteId;
    protected int serverId;
}

@Entity
public class Employee implements Serializable {

    @EmbeddedId
    private EmployeeId id;

    private String firstName;

    @ManyToOne
    @MapsId("serverId")
    private Server server;

    @OneToOne
    @MapsId("websiteId")
    private Website website;

    public Employee() {}

    public Employee(String firstName, Server server, Website website) {
        this.firstName = firstName;
        this.server = server;
        this.website = website;
    }
}

Теперь у меня есть простой метод тестирования, написанный на Java SE (обратите внимание, что это обычный класс, выполняемый из статического основного метода - это , а не класс JUnit):

private void executeTest() {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("standaloneTests");

    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();

    tx.begin();

    Server s = new Server("BigServer");
    em.persist(s);

    Website w = new Website("domain.com");
    em.persist(w);

    Employee e = new Employee("John", s, w);
    em.persist(e);

    tx.commit();

    em.close();
    emf.close();
}

Как вы можете видеть, я не делаю здесь ничего необычного - просто установите сущности в объекте Employee и сохраните его. Как я понимаю, аннотация @MapsId должна отражать состояние аннотированной сущности в EmbeddedId.

Теперь проблема в том, что в EclipseLink все работает гладко и сущности сохраняются должным образом. Когда я меняю провайдера JPA 2.0 на Hibernate (4.0 CR5), он выдает PropertyAccessException :

Исключение в потоке "main" javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: не удалось установить значение поля установка отражения com.test.entities.EmployeeId.serverId в org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManagerImpl.java:1353) в org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManagerImpl.java:1281) в org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManagerImpl.java:1287) в org.hibernate.ejb.AbstractEntityManagerImpl.persist (AbstractEntityManagerImpl.java:853) на com.test.Standalone.executeTest (Standalone.java:101) на com.test.Standalone.main (Standalone.java:35) Причина: org.hibernate.PropertyAccessException: не удалось установить значение поля установка отражения com.test.entities.EmployeeId.serverId в org.hibernate.property.DirectPropertyAccessor $ DirectSetter.set (DirectPropertyAccessor.java:150) в org.hibernate.mapping.Component $ ValueGenerationPlan.execute (Component.java:436) в org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate (CompositeNestedGeneratedValueGenerator.java:121) в org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId (AbstractSaveEventListener.java:120) в org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId (EJB3PersistEventListener.java:78) в org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient (DefaultPersistEventListener.java:180) в org.hibernate.event.internal.DefaultPersistEventListener.onPersist (DefaultPersistEventListener.java:136) в org.hibernate.event.internal.DefaultPersistEventListener.onPersist (DefaultPersistEventListener.java:64) в org.hibernate.internal.SessionImpl.firePersist (SessionImpl.java:729) в org.hibernate.internal.SessionImpl.persist (SessionImpl.java:705) в org.hibernate.internal.SessionImpl.persist (SessionImpl.java:709) в org.hibernate.ejb.AbstractEntityManagerImpl.persist (AbstractEntityManagerImpl.java:847) ... еще 2 Причины: java.lang.NullPointerException at sun.reflect.UnsafeFieldAccessorImpl.ensureObj (UnsafeFieldAccessorImpl.java:36) в sun.reflect.UnsafeIntegerFieldAccessorImpl.set (UnsafeIntegerFieldAccessorImpl.java:57) в java.lang.reflect.Field.set (Field.java:657) в org.hibernate.property.DirectPropertyAccessor $ DirectSetter.set (DirectPropertyAccessor.java:138) ... еще 13

Я не знаю, откуда может появиться исключение NullPointerException - как вы можете видеть, все свойства сущности установлены.

Я даже не знаю , зачем Hibernate нужен установщик , но просто чтобы убедиться, что я предоставил установщики для каждого поля (включая идентификаторы) для Employee, Website и Server сущностей.Как и ожидалось - ничего не изменилось, и Hibernate все еще не может найти (уже присутствует) сеттер.

Как вы думаете, это может быть какая-то ошибка или я просто не понял какую-то часть контракта JPA 2.0?

Заранее спасибо!

Ответы [ 3 ]

15 голосов
/ 14 марта 2014

Решение Здесь : возникла та же проблема, и теперь работает .

Чтобы это работало, EmployeeId вашего класса Employee должен быть создан либо в конструкторе Employee, либо в SessionBean перед созданием персистентности.

В противном случае он пытается заполнить значения вашего внедренного значения нулем.

Не уверен, нормально ли это или плохая реализация спецификаций JPA. Я думаю, что последнее, так как конструктор для вашего ПК определен и hibernate должен вызывать его сам по себе.

5 голосов
/ 02 ноября 2011

См. этот вопрос.В нем просто говорится, что

org.hibernate.PropertyAccessException может быть выдано, если сущность содержит следующие условия:

  1. Использует @EmbeddedId
  2. Использует @JoinTableдля свойства / поля коллекции или ассоциации, которое ссылается на другое свойство / поле объекта.немного странно.
2 голосов
/ 12 июня 2013

это старый, но может быть полезным для некоторых

попытаться

@Entity
public class Employee implements Serializable {

@EmbeddedId
private EmployeeId id;

private String firstName;

@ManyToOne
@MapsId("id")
@JoinColumn(name ="serverId")
private Server server;

@OneToOne
@MapsId("id")
@JoinColumn(name= "websiteId")
private Website website;
...