【问题标题】:Is there a way in Hibernate to obtain an entity's loaded PersistentCollection without loading the entire entity object first?Hibernate 有没有办法在不首先加载整个实体对象的情况下获取实体加载的 PersistentCollection?
【发布时间】:2010-10-30 18:36:20
【问题描述】:

这是一个谜题! :D

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

让我更好地解释一下。我有一个这样注释的角色实体:

@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(permissions);强制初始化集合。

但是,我需要一种无需先加载角色实体即可完成相同任务的方法。我知道我需要权限集合的实体的 ID,以及集合的角色 (temp.pack.Role.permissions)。

有没有办法做到这一点?我希望避免访问数据库来检索角色对象的所有字段(很多!)只是为了获取集合并将它们全部丢弃。

我可以使用连接,但这让我可以访问权限对象本身,而不是我需要的实际 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 而失败

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

【问题讨论】:

  • 是什么让您认为当您只关心角色对象的子集合时,不加载角色对象的字段实际上是在节省任何东西?从 Roles 行中选择额外的字段应该不会真的很昂贵。这听起来像是过早的优化。坦率地说,这听起来不值得付出这样的努力。
  • @matt b:嗨!谢谢你的评论。我只是决定保持原样,加载那个实体真的不太贵。现在我加载实体,获取我需要的集合并丢弃实体。谢谢!
  • 这个问题仍然没有解决。现在我将使用建议的解决方案,但它们是解决方法,而不是真正的答案。我不确定在 Hibernate 中有没有简单的方法可以做到这一点,但我最近广泛调试了 Hibernate,我相信有办法。我现在不会再花时间研究这个了,但如果你知道答案,请发布它,我会将其标记为已接受。

标签: java hibernate internals


【解决方案1】:

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

19.1.7. Using lazy property fetching

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

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

【讨论】:

  • 嗨!感谢您的回复。我需要的实际上不是一种延迟加载属性的方法,而是只检索一个属性集合而不加载所有者实体。我发现这只是花费了太长时间,并且查询该实体(正如其他 cmets 所指出的那样)并不昂贵,所以我决定保持原样。现在我加载实体,获取我需要的集合并丢弃实体。还是谢谢你!
猜你喜欢
  • 1970-01-01
  • 2013-01-08
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 1970-01-01
  • 2017-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多