在Hibernate中有没有办法获得实体加载的PersistentCollection而不先加载整个实体对象?

时间:2010-10-30 18:36:20

标签: java hibernate internals

这是一个益智游戏! :d

有没有办法强制Hibernate为实体加载集合而不先加载整个实体?

让我解释得更好。我有一个以这种方式注释的Role实体:

@Entity(name="Role")
@Table(name = "ROLES")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@javax.persistence.TableGenerator(
 name="GENERATED_IDS",
 table="GENERATED_IDS",
    valueColumnName = "ID"
)
public abstract class Role implements Serializable {
 private static final long serialVersionUID = 1L;


 /**
  * The id of this role. Internal use only.
  * 
  * @since 1.0
  */
 @Id @GeneratedValue(strategy = GenerationType.TABLE, generator="GENERATED_IDS")
 @Column(name = "ROLE_ID")
 protected long id;


 /**
  * Set of permissions granted to this role.
  * 
  * @since 1.0
  */
 @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy="sourceRole")
 protected Set<Permission> permissions = new HashSet<Permission>();

...

}

当我通过执行以下操作访问权限集合时:

Role role = ...
Set permissions = role.getPermission();

Hibernate使用其PersistentCollection子类之一包装返回的集合。然后我可以使用Hibernate.initialize(权限);强制收集初始化。

但是,我需要的是在不首先加载角色实体的情况下实现相同目的的方法。我知道我需要权限集合的实体的id,以及集合的角色(temp.pack.Role.permissions)。

有办法吗?我希望避免命中数据库来检索Role对象的所有字段(很多!)只是为了获取集合并将它们全部丢弃。

我可以使用连接,但这使我可以访问权限对象本身,而不是我需要的实际PersistentCollection包装器。

我试过了:

Session session = connectionInfoProvider.getSession(); 

// this is just "permissions", the collection field name
String attributeName = role.substring(role.lastIndexOf(".")+1, role.length()); 

// this is the Role class name, temp.pack.Role
String entityClassName = role.substring(0, role.lastIndexOf("."));
Class<?> roleClass = Class.forName(entityClassName);

Field collectionField = roleClass.getDeclaredField(attributeName);
collectionField.setAccessible(true);
Hibernate.initialize(collection);

但没有奏效。我得到的集合只是一个常规的空集,没有任何东西被加载。

我也试过这个:

Session session = connectionInfoProvider.getSession();

// this is just "permissions", the collection field name
String attributeName = role.substring(role.lastIndexOf(".")+1, role.length());

// this is the Role class name, temp.pack.Role
String entityClassName = role.substring(0, role.lastIndexOf("."));
Class<?> roleClass = Class.forName(entityClassName);

Field collectionField = roleClass.getDeclaredField(attributeName);
collectionField.setAccessible(true);
Object object = session.load(roleClass, id);
ProxyObject objectProxy = (ProxyObject)object;
LazyInitializer lazyInitializer = (LazyInitializer)objectProxy.getHandler();

Object objectImpl = lazyInitializer.getImplementation();
Object collection = collectionField.get(objectImpl);
Hibernate.initialize(collection);

但也没有用,它失败了java.lang.IllegalArgumentException: unknown handler key

我也尝试过:

PersistenceContext context = ((SessionImplementor)currSession).getPersistenceContext();
CollectionPersister persister = ((SessionFactoryImplementor) sessFactory) .getCollectionPersister(role);
CollectionKey key = new CollectionKey(persister, id, EntityMode.POJO);
// collection - contains set containing actual data
PersistentCollection collection = context.getCollection(key);

java.lang.IllegalArgumentException: unknown handler key

也失败了

关于如何实现这一目标的任何想法?

1 个答案:

答案 0 :(得分:1)

好吧,你可以使事情变得复杂并使用lazy fetching of properties(这需要字节码检测)。但是,让我引用文档:

  

19.1.7. Using lazy property fetching

     

Hibernate3支持延迟抓取   个人财产。这个   优化技术也是已知的   作为获取组。 请注意   这主要是营销功能;   优化行读取更多   比柱优化更重要   读取即可。但是,只加载一些   类的属性可能很有用   在极端的情况下。例如,何时   遗留表有数百列   并且数据模型无法改进。

所以在采用这条路径之前,我首先要确保加载这些属性确实是一个问题。