Вставка значения в «другую сторону» отношения 1: n в JPA (с использованием EclipseLink) - PullRequest
2 голосов
/ 23 марта 2011

У меня есть приложение, использующее JSF 2, JPA 2 и EJB 3.1, работающее на GlassFish v3 (поэтому оно использует EclipseLink 2). Это приложение имеет два объекта JPA, Person и Message, и каждый Message имеет ссылку на два Person s, отправителя сообщения и получателя сообщения. Класс Person имеет атрибуты, обеспечивающие доступ к отправленным или полученным Message с. Класс Message выглядит примерно так:

@Entity
public class Message {
    @ManyToOne
    @JoinColumn(name="sender")
    private Person sender;

    @ManyToOne
    @JoinColumn(name="receiver")
    private Person receiver;
    // ... some stuff ...
}

и класс Person похож на следующий:

@Entity
public class Person {
    @OneToMany(fetch=FetchType.EAGER, mappedBy="sender")
    private List<Message> sentMessages;

    @OneToMany(fetch=FetchType.EAGER, mappedBy="receiver")
    private List<Message> receivedMessages;
    // ... more stuff ...
}

Message экземпляры создаются с помощью метода в классе DAO:

@Stateless
public class MessageDAOImpl implements MessageDAO {
    public Message crete(Person sender, Person receiver) {
        Message message = new Message();
        message.setSender(sender);
        message.setReceiver(receiver);
        entityManager.persist(message);
        // Puting in other objects, hoping it will work
        sender.getSentMessages().add(message);
        receiver.getReceivedMessages().add(message);

        // Saving sender and receiver: here comes the interesting part
        entityManager.merge(sender);    // [1]
        entityManager.merge(receiver); // [2]
        return message;
    }
}

Однако происходит нечто удивительное. Когда я закомментирую строки, помеченные [1] и [2], и вызываю метод, сообщение не появляется в отправленных сообщениях sender и списках полученных сообщений receiver, когда я использую эти объекты в другом месте, даже если они извлекаются из менеджера сущностей (например, через EntityManager.find()). Если я раскомментирую его, то сообщение будет присутствовать в списках, как и ожидалось.

Я нахожу это интригующим, потому что я представляю две ситуации для случая, когда строки закомментированы:

  • сущности sender и receiver извлекаются напрямую из базы данных, и сообщение должно появиться в их списках, потому что я сохранил сообщение и, следовательно, связь сохраняется в базе данных; или
  • сущности sender и receiver извлекаются из некоторого кэша, поэтому в них уже добавлены сообщения.

Видимо, так не работает.

Я нашел эту потрясающую статью о кеше в Hibernate. Исходя из этого, я размышляю о том, что проблема заключается в том, что, поскольку кэш состоит не из объектов, а из значений, требуется метод EntityManager.merge() для «обновления» сущностей с помощью кэшированных значений.

Это так? Если нет, то в чем причина такого поведения? Является ли звонок EntityManager.merge() лучшим решением?

Спасибо всем заранее!

Ответы [ 2 ]

3 голосов
/ 24 марта 2011

Проблема в том, что вы нарушаете личность объекта. Ваши персональные объекты поступают из другой транзакции, поэтому из другой единицы персистентности они отсоединяются. Ссылаясь на них из вашего нового сообщения, вы повредили свой блок персистентности, потому что теперь вы можете ссылаться на отсоединенные объекты от управляемых объектов. то есть, если вы выполните find () для любого человека, вы получите другого человека обратно.

Вы должны либо сначала найти () каждого человека в текущем контексте транзакции / персистентности, а затем создать сообщение с ними, либо использовать merge () в новом сообщении вместо persist () как объединение с разрешенными отсоединенными объектами.

Причина, по которой объекты сообщений отсутствуют в сообщениях человека после создания, заключается в том, что вы используете общий кэш (по умолчанию с EclipseLink), и без слияния вы никогда не добавляли сообщения в объекты управляемого лица (только отключенные). из них). Поскольку ManyToOne определяет отношения в базе данных, вы можете отключить кэширование или вызвать обновление для этого человека и получить правильные сообщения. Но правильное решение - не портить вашу объектную модель.

См http://en.wikibooks.org/wiki/Java_Persistence/Caching#Object_Identity

0 голосов
/ 23 марта 2011

Я понимаю, что сущности получателя и отправителя не сохраняются автоматически в базе данных при сохранении вашего сообщения.

Я думаю, что вы должны правильно настроить параметры каскадирования.Может быть, эта статья может помочь.

http://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/

...