【发布时间】:2016-04-25 04:36:37
【问题描述】:
有没有办法获取当前附加在实体管理器中的所有对象?
我想编写一些监控代码来报告附加对象的数量及其类。
意思是查找之前查询加载的所有对象,并将操作查找到实体管理器中。
我正在使用EclipseLink,所以具体的解决方案也很好。
【问题讨论】:
标签: jpa eclipselink entitymanager
有没有办法获取当前附加在实体管理器中的所有对象?
我想编写一些监控代码来报告附加对象的数量及其类。
意思是查找之前查询加载的所有对象,并将操作查找到实体管理器中。
我正在使用EclipseLink,所以具体的解决方案也很好。
【问题讨论】:
标签: jpa eclipselink entitymanager
EclipseLink 的 JPA 接口几乎包装了它的本机代码,因此 EntityManager 在下面使用 UnitOfWork 会话(而 EMF 包装了一个 ServerSession)。如果您想查看 UnitOfWork 管理的实体,您需要访问 UnitOfWork。
如果使用 JPA 2.0,可以使用 EntityManager 展开方法:
UnitOfWork uow = em.unwrap(UnitOfWork.class);
否则,使用一些强制转换
UnitOfWork uow = ((EntityManagerImpl)em).getUnitOfWork();
从那里,UnitOfWork 拥有所有已注册(也称为托管)实体的列表。您可以使用 UOW 直接使用printRegisteredObjects() 方法记录它所拥有的内容,或者使用getCloneMapping().keySet() 自己获取它。
您还可以使用hasDeletedObjects() 和getDeletedObjects().keySet()(如果有)来查看已删除的对象,对于使用hasNewObjectsInParentOriginalToClone() 和getNewObjectsCloneToOriginal().keySet() 的新对象也是如此
【讨论】:
您可以通过很多我还不知道的方式使用 JPA,并且在 eclipselink 的幕后发生了很多我仍然不完全理解的事情,但看起来有可能看到持久性语境。使用此代码需您自担风险。它只是为了给您一个提示,即可以检查上下文。 (无论代码是对还是错,我都会发布它,因为当我试图决定是否使用 eclipselink 时它会对我有所帮助。关于如何正确执行此操作的文档方式似乎并不多。 )
public void saveChanges() {
Date now = new Date();
JpaEntityManager jem = em.unwrap(JpaEntityManager.class);
UnitOfWorkImpl uow = jem.unwrap(UnitOfWorkImpl.class);
// inserts
for (Object entity : uow.getNewObjectsCloneToOriginal().keySet()) {
if (entity instanceof IAuditedEntity) {
IAuditedEntity auditedEntity = (IAuditedEntity) entity;
auditedEntity.setAuditedUserId(this.userId);
auditedEntity.setAuditedAt(now);
auditedEntity.setCreatedAt(now);
}
}
// updates
UnitOfWorkChangeSet uowChangeSet = (UnitOfWorkChangeSet) uow.getUnitOfWorkChangeSet();
if (uowChangeSet != null) {
List<IAuditedEntity> toUpdate = new ArrayList<>();
for(Entry<Object, ObjectChangeSet> entry : uowChangeSet.getCloneToObjectChangeSet().entrySet()) {
if (entry.getValue().hasChanges()) {
if (entry.getKey() instanceof IAuditedEntity) {
toUpdate.add((IAuditedEntity) entry.getKey());
}
}
}
for (IAuditedEntity auditedEntity : toUpdate) {
auditedEntity.setAuditedUserId(this.userId);
auditedEntity.setAuditedAt(now);
}
}
// deletions
Project jpaProject = uow.getProject();
boolean anyAuditedDeletions = false;
for (Object entity : uow.getDeletedObjects().keySet()) {
if (entity instanceof IAuditedEntity) {
anyAuditedDeletions = true;
DeletedEntity deletion = new DeletedEntity();
deletion.setTableName(jpaProject.getClassDescriptor(entity.getClass()).getTableName());
deletion.setEntityId(((IAuditedEntity) entity).getId());
deletion.setAuditedUserId(this.userId);
em.persist(deletion);
}
}
}
【讨论】:
您可以通过检查MetaModel 上的实体来实现这一点,这些实体可以从任何EntityManager 获得。
使用示例:
EntityManager em = // get your EM however...
for(EntityType<?> entityType : em.getMetaModel().getEntities())
{
Class<?> managedClass = entityType.getBindableJavaType();
System.out.println("Managing type: " + managedClass.getCanonicalName());
}
此示例将打印出由 EntityManager 管理的所有类类型。要获取所有被管理的实际对象,只需在 EntityManager 上查询该类型的所有对象。
更新:
从 JPA 2.0 开始,您可以缓存将由 javax.persistence.Cache 管理的结果。但是,使用纯 JPA 无法实际检索存储在缓存中的对象,您可以做的最好的事情是通过 Cache.contains(Class cls, Object pk) 检查某个对象是否在缓存中:
em.getEntityManagerFactory().getCache().contains(MyData.class, somePK);
但是,EclipseLink 将Cache 扩展为JpaCache。您可以使用它通过JpaCache.getObject(Class cls, Object id) 从缓存中实际获取对象。这不会返回集合或任何东西,但它是次优的。
不幸的是,如果您想实际访问缓存中的对象,则需要自己管理。
【讨论】:
cache.getAllObjects() 方法一样快。
我在EntityManager 界面中没有看到这样的选项。只有一个contains(Object entity) 方法,但您需要传递具体对象,并且它们在 PersistenceContext 中被检查是否存在。还在查看PersistenceContext 界面,我没有看到这样的选项。
【讨论】: