问题
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 = 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?
回答1:
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.
来源:https://stackoverflow.com/questions/4060126/is-there-a-way-in-hibernate-to-obtain-an-entitys-loaded-persistentcollection-wi