开发者

Is there a way in Hibernate to obtain an entity's loaded PersistentCollection without loading the entire entity object first?

This is a puzzler! :D

Is there a way to force Hibernate to load a collection for an entity without loading the entire entity first?

Let m explain better. I have a Role entity annotated this way:

@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>();

...

}

When I access the permissions collection by doing:

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

Hibernate wraps the returned collection with one of its subclasses of PersistentCollection. I can then use Hibernate.initialize(permissions); to force the collection to be initialized.

However, what I need is a way to accomplish the same without first loading the role entity. I know the id for the entity I need the permissions collections for, and the Role for the collection (temp.pack.Role.permissions).

Is there a way to do that? I wold like to avoid hitting the database to retrieve all fields of the Role object (many!) just to get the collection and discard them all.

I could use a join, but that givens me access to the permission objects themselves, not the actual PersistentCollection wrapper which the one I need.

I tried this:

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);

But didn't work. The collection I get is just a regular empty set and nothing is loaded.

I also tried this:

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);

But also didn't work, it fails with java.lang.IllegalArgumentException: unknown handler key.

I also tried:

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

But also fails with java.lang.IllegalArgumentException: unknown handler key

Any ideas on how to accomplish this?


Well, you could make things complicated and use lazy fetching of properties (which requires bytecode instrumentation). But let me quote the documentation:

19.1.7. Using lazy property fetching

Hibernate3 supports the lazy fetching of individual properties. This optimization technique is also known as fetch groups. Please note that this is mostly a marketing feature; optimizing row reads is much more important than optimization of column reads. However, only loading some properties of a class could be useful in extreme cases. For example, when legacy tables have hundreds of columns and the data model cannot be improved.

So before to take this path, I would first make sure that loading these properties is really a concern.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜