Отсоединить объект от контекста постоянства JPA/EJB3
Каким будет самый простой способ отсоединить конкретный объект JPA Bean, который был получен через EntityManager. В качестве альтернативы, может ли я иметь запрос возврата отдельных объектов в первую очередь, чтобы они по существу действовали как "только для чтения"?
Причина, по которой я хочу сделать это, состоит в том, что я хочу изменить данные в Bean - только в моем приложении, но никогда не сохранял его в базе данных. В моей программе мне, в конечном счете, нужно вызвать flush() в EntityManager, который сохранит все изменения от прикрепленных объектов в базе данных underyling, но я хочу исключить определенные объекты.
Ответы
Ответ 1
К сожалению, нет способа отключить один объект от менеджера объектов в текущей реализации JPA, AFAIR.
EntityManager.clear() отключит все объекты JPA, так что это может быть не подходящее решение во всех случаях, если у вас есть другие объекты, которые вы планируете поддерживать.
Итак, лучше всего будет клонировать объекты и передавать клоны на код, который изменяет объекты. Поскольку примитивные и неизменяемые поля объектов тщательно обрабатываются механизмом клонирования по умолчанию, вам не нужно будет писать много сантехнического кода (кроме глубокого клонирования любых агрегированных структур, которые у вас могут быть).
Ответ 2
(может быть, слишком поздно для ответа, но может быть полезным для других)
Я разрабатываю свою первую систему с JPA прямо сейчас. К сожалению, я столкнулся с этой проблемой, когда эта система почти завершена.
Проще говоря. Используйте Hibernate или подождите JPA 2.0.
В Hibernate вы можете использовать 'session.evict(object)' для удаления одного объекта из сеанса. В JPA 2.0, в проекте прямо сейчас, существует метод EntityManager.detach(object) 'для отсоединения один объект из контекста персистентности.
Ответ 3
Независимо от того, какую реализацию JPA вы используете, просто используйте entityManager.detach(object)
теперь в JPA 2.0 и части JEE6.
Ответ 4
Если вам нужно отделить объект от EntityManager, и вы используете Hibernate в качестве базового уровня ORM, вы можете получить доступ к сеансу Session.evict(Object), о котором упомянул Маурисио Канада.
public void detach(Object entity) {
org.hibernate.Session session = (Session) entityManager.getDelegate();
session.evict(entity);
}
Конечно, это сломается, если вы перейдете на другой провайдер ORM, но я думаю, что это желательно сделать глубокую копию.
Ответ 5
Насколько я знаю, единственные прямые способы сделать это:
- Зафиксировать txn - Вероятно, не разумный вариант
- Очистить контекст сохранения - EntityManager.clear() - Это жестоко, но очистит его
- Скопировать объект. Большую часть времени ваши объекты JPA сериализуются, поэтому это должно быть легко (если не особенно эффективно).
Ответ 6
При использовании EclipseLink
у вас также есть параметры,
Используйте подсказку запроса, eclipselink.maintain-cache"="false
- все возвращенные объекты будут отсоединены.
Используйте EclipseLink
JpaEntityManager
copy()
API для копирования объекта на нужную глубину.
Ответ 7
Если в bean не так много свойств, вы можете просто создать новый экземпляр и установить все его свойства вручную из сохраненного bean.
Это может быть реализовано как конструктор копирования, например:
public Thing(Thing oldBean) {
this.setPropertyOne(oldBean.getPropertyOne());
// and so on
}
Тогда:
Thing newBean = new Thing(oldBean);
Ответ 8
Маурисио Канада, благодаря вам за этот совет, метод evict() работает хорошо. Я использую JPA из SEAM, там поддерживается поддержка JPA Entity Manager, и есть возможность получить доступ к сеансу делегата спящего режима и, таким образом, этот метод "выселить".
Большое спасибо, Zmicer
Ответ 9
это быстро и грязно, но вы также можете сериализовать и десериализовать объект.
Ответ 10
Поскольку я использую SEAM и JPA 1.0, и моя система имеет фьюксинцию, которая должна регистрировать все изменения полей, я создал объект значения или объект передачи данных, если те же поля объекта, которые должны быть зарегистрированы. Конструктор нового pojo:
public DocumentoAntigoDTO(Documento documentoAtual) {
Method[] metodosDocumento = Documento.class.getMethods();
for(Method metodo:metodosDocumento){
if(metodo.getName().contains("get")){
try {
Object resultadoInvoke = metodo.invoke(documentoAtual,null);
Method[] metodosDocumentoAntigo = DocumentoAntigoDTO.class.getMethods();
for(Method metodoAntigo : metodosDocumentoAntigo){
String metodSetName = "set" + metodo.getName().substring(3);
if(metodoAntigo.getName().equals(metodSetName)){
metodoAntigo.invoke(this, resultadoInvoke);
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
Ответ 11
В JPA 1.0 (проверено с использованием EclipseLink) вы можете получить объект за пределами транзакции. Например, с транзакциями, управляемыми контейнерами, вы можете сделать:
public MyEntity myMethod(long id) {
final MyEntity myEntity = retrieve(id);
// myEntity is detached here
}
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public MyEntity retrieve(long id) {
return entityManager.find(MyEntity.class, id);
}
Ответ 12
Имею дело с подобным случаем, я создал объект DTO, который расширяет объект постоянной сущности следующим образом:
class MyEntity
{
public static class MyEntityDO extends MyEntity {}
}
Наконец, скалярный запрос будет извлекать требуемые не управляемые атрибуты:
(Hibernate) select p.id, p.name from MyEntity P
(JPA) select new MyEntity(p.id, p.name) from myEntity P
Ответ 13
Если вы попадете сюда, потому что вы действительно хотите передать объект через удаленную границу, вы просто вставляете код для обмана hibernazi.
for(RssItem i : result.getChannel().getItem()){
}
Cloneable не работает, потому что он фактически копирует PersistantBag.
И забудьте об использовании потоков serializable и bytearray и потоковых потоков. создание потоков во избежание тупиков убивает всю концепцию.
Ответ 14
Я думаю, вы также можете использовать метод EntityManager.refresh(Object o), если первичный ключ объекта не был изменен. Этот метод восстановит исходное состояние объекта.