Каким будет самый простой способ отсоединить конкретный объектный компонент JPA, который был получен через EntityManager. В качестве альтернативы, могу ли я сделать так, чтобы запрос возвращал отдельные объекты, чтобы они по существу действовали как «только для чтения»?
Причина, по которой я хочу это сделать, заключается в том, что я хочу изменить данные внутри bean-компонента - только в моем приложении, но никогда не сохраняю их в базе данных. В моей программе мне в конечном итоге приходится вызывать flush () для EntityManager, который сохранял бы все изменения из присоединенных сущностей в базе данных underyling, но я хочу исключить определенные объекты.




Насколько мне известно, единственные прямые способы сделать это:
Если в компоненте не слишком много свойств, вы можете просто создать новый экземпляр и установить все его свойства вручную из постоянного компонента.
Это может быть реализовано как конструктор копирования, например:
public Thing(Thing oldBean) {
this.setPropertyOne(oldBean.getPropertyOne());
// and so on
}
Потом:
Thing newBean = new Thing(oldBean);
К сожалению, в текущей реализации JPA, AFAIR, нет способа отключить один объект от диспетчера сущностей.
EntityManager.clear () отключит все объекты JPA, поэтому это может быть не подходящим решением во всех случаях, если у вас есть другие объекты, которые вы планируете поддерживать.
Поэтому лучше всего клонировать объекты и передавать клоны в код, который изменяет объекты. Поскольку о примитивных и неизменяемых полях объектов должным образом позаботится механизм клонирования по умолчанию, вам не придется писать много связующего кода (кроме глубокого клонирования любых агрегированных структур, которые у вас могут быть).
Это больше не так, теперь EM предоставляет метод отсоединения (сущности), начиная с JPA v2, см. Javax.persistence.EntityManager # detach
(может быть поздно отвечать, но может быть полезно другим)
Я разрабатываю свою первую систему с JPA прямо сейчас. К сожалению, я столкнулся с этой проблемой, когда эта система почти завершена.
Проще говоря. Используйте Hibernate или дождитесь JPA 2.0.
В Hibernate вы можете использовать session.evict (object) для удаления одного объекта из сеанса. В JPA 2.0, в черновике прямо сейчас, есть метод EntityManager.detach (object) для отделения одного объекта от контекста постоянства.
Сейчас ровно год спустя. У меня возникла эта проблема, и я не могу найти вызов метода «отсоединения» в EntityManager. По какой-то причине его уронили?
Здесь download.oracle.com/javaee/6/api/javax/persistence/…
это быстро и грязно, но вы также можете сериализовать и десериализовать объект.
Предупреждаем, это может вызвать проблемы с отложенной загрузкой и отношениями JPA.
Я думаю, вы также можете использовать метод EntityManager.refresh (Object o), если первичный ключ объекта не был изменен. Этот метод восстановит исходное состояние объекта.
Если вам нужно отсоединить объект от EntityManager и вы используете Hibernate в качестве базового уровня ORM, вы можете получить доступ к объекту Сессия гибернации и использовать метод Session.evict (Объект), упомянутый выше Маурисио Канадой.
public void detach(Object entity) {
org.hibernate.Session session = (Session) entityManager.getDelegate();
session.evict(entity);
}
Конечно, это сломается, если вы переключитесь на другого поставщика ORM, но я думаю, что это лучше, чем попытаться сделать глубокую копию.
Поскольку я использую 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();
}
}
}
}
Если вы используете EclipseLink, у вас также есть варианты,
Используйте подсказку запроса, eclipselink.maintain-cache" = "false - все возвращенные объекты будут отсоединены.
Используйте EclipseLinkJpaEntityManagercopy() API, чтобы скопировать объект на желаемую глубину.
Если вы попали сюда, потому что действительно хотите передать объект через удаленную границу, вы просто вставляете код, чтобы обмануть спящего.
for(RssItem i : result.getChannel().getItem()){
}
Cloneable не будет работать, потому что он фактически копирует PersistantBag.
И забудьте об использовании сериализуемых потоков, потоков с байтовыми массивами и конвейерных потоков. создание потоков во избежание взаимоблокировок убивает всю концепцию.
Независимо от того, какую реализацию JPA вы используете, просто используйте entityManager.detach(object), он теперь в JPA 2.0 и является частью JEE6.
В 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);
}
В аналогичном случае я создал объект 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
Я думаю, что есть способ выселить один объект из EntityManager, вызвав это
EntityManagerFactory emf;
emf.getCache().evict(Entity);
Это удалит конкретную сущность из кеша.
Это только вытесняет объект из кеша второго уровня, но не из кеша сеанса.
Как фиксация txn вызывает отсоединение объекта?