防止Dozer触发Hibernate延迟加载 [英] Prevent Dozer from triggering Hibernate lazy loading

查看:185
本文介绍了防止Dozer触发Hibernate延迟加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我想阻止Dozer触发延迟加载,这样就隐藏了SQL查询永远不会发生:所有抓取都必须通过HQL明确完成(以获得对性能的最佳控制)。


  1. 这是一个很好的做法(我无法在任何地方找到它)?


  2. 如何安全地做到这一点?

  3. b

    我在DTO转换之前试过这个:

      PlatformTransactionManager tm = (PlatformTransactionManager)SingletonFactoryProvider.getSingletonFactory()。getSingleton(transactionManager); 
    tm.commit(tm.getTransaction(new DefaultTransactionDefinition()));

    我不知道事务会发生什么,但Hibernate会话没有关闭,

    我试过这个:

      SessionFactory sf =(SessionFactory)SingletonFactoryProvider.getSingletonFactory()。getSingleton(sessionFactory); 
    sf.getCurrentSession()。clear();
    sf.getCurrentSession()。close();

    它可以防止延迟加载,但在应用程序层中直接操作会话是一种很好的做法在我的项目中被称为门面)?我应该害怕哪种负面影响? (我已经看到涉及POJO - > DTO转换的测试不能再通过AbstractTransactionnalDatasource Spring测试类来启动,因为这些类试图触发对没有更多链接到活动会话的事务的回滚)。



    我也尝试将传播设置为NOT_SUPPORTED或REQUIRES_NEW,但它重复使用当前的Hibernate会话,并且不会阻止延迟加载。
    <解决方案我已经找到的唯一通用解决方案(查看自定义转换器,事件监听器和代理解析器后)是通过实现自定义字段映射器来实现的。我发现这个功能隐藏在Dozer API中(我不相信它被记录在用户指南中)。



    一个简单的例子如下:

     公共类MyCustomFieldMapper实现CustomFieldMapper 
    {
    公共布尔MapField可(对象源,对象目的地,对象sourceFieldValue,类映射类映射,FieldMap fieldMapping)
    {
    //检查字段是否为Hibernate集合代理
    if(!(sourceFieldValue instanceof AbstractPersistentCollection)){
    //允许推土机以正常映射
    返回false;


    //检查字段是否已经初始化
    if(((PersistentSet)sourceFieldValue).wasInitialized()){
    //允许推土机映射为正常
    返回false;
    }

    //将目的地设置为空,并告诉推土机该字段已被映射
    destination = null;
    返回true;






    $ b

    这会将任何未初始化的PersistentSet对象返回为null 。我这样做是为了当它们传递给客户端时,我可以区分NULL(未加载)集合和空集合。这允许我在客户端中定义通用行为,以使用预加载的集合,或者进行另一个服务调用来检索集合(如果需要)。此外,如果您决定在服务层中加载任何集合,那么它们将照常进行映射。



    我使用spring注入自定义字段映射器:

     < bean id =dozerMapperclass =org.dozer.DozerBeanMapperlazy-init =false> 
    < property name =mappingFiles>
    ...
    < / property>
    < property name =customFieldMapperref =dozerCustomFieldMapper/>
    < / bean>
    < bean id =dozerCustomFieldMapperclass =my.project.MyCustomFieldMapper/>

    我希望这可以帮助任何人寻找解决方案,因为我在搜索时找不到任何示例互联网。

    I am using Spring transactions so the transaction is still active when POJO to DTO conversion occurs.

    I would like to prevent Dozer from triggering lazy loading, so that hidden sql queries never occur : all fetching has to be done explicitly via HQL (to get the best control on performances).

    1. Is it a good practice (I can't find it documented anywhere) ?

    2. How to do it safely ?

    I tried this before DTO conversion :

    PlatformTransactionManager tm = (PlatformTransactionManager) SingletonFactoryProvider.getSingletonFactory().getSingleton("transactionManager");
    tm.commit(tm.getTransaction(new DefaultTransactionDefinition()));
    

    I don't know what happens to the transaction, but the Hibernate session doesn't get closed, and the lazy loading still occurs.

    I tried this :

    SessionFactory sf = (SessionFactory) SingletonFactoryProvider.getSingletonFactory().getSingleton("sessionFactory");
    sf.getCurrentSession().clear();
    sf.getCurrentSession().close();
    

    And it prevents lazy loading, but is it a good practice to manipulate session directly in the application layer (which is called "facade" in my project) ? Which negative side effects should I fear ? (I've already seen that tests involving POJO -> DTO conversions could no more be launched through AbstractTransactionnalDatasource Spring test classes, because this classes try to trigger a rollback on a transaction which is no more linked to an active session).

    I've also tried to set propagation to NOT_SUPPORTED or REQUIRES_NEW, but it reuse the current Hibernate session, and doesn't prevent lazy loading.

    解决方案

    The only generic solution I have found for managing this (after looking into Custom Converters, Event Listeners & Proxy Resolvers) is by implementing a Custom Field Mapper. I found this functionality tucked away in the Dozer API (I don't believe it is documented in the User Guide).

    A simple example is as follows;

    public class MyCustomFieldMapper implements CustomFieldMapper 
    {
        public boolean mapField(Object source, Object destination, Object sourceFieldValue, ClassMap classMap, FieldMap fieldMapping) 
        {       
            // Check if field is a Hibernate collection proxy
            if (!(sourceFieldValue instanceof AbstractPersistentCollection)) {
                // Allow dozer to map as normal
                return false;
            }
    
            // Check if field is already initialized
            if (((PersistentSet) sourceFieldValue).wasInitialized()) {
                // Allow dozer to map as normal
                return false;
            }
    
            // Set destination to null, and tell dozer that the field is mapped
            destination = null;
            return true;
        }   
    }
    

    This will return any non-initialized PersistentSet objects as null. I do this so that when they are passed to the client I can differentiate between a NULL (non-loaded) collection and an empty collection. This allows me to define generic behaviour in the client to either use the pre-loaded set, or make another service call to retrieve the set (if required). Additionally, if you decide to eagerly load any collections within the service layer then they will be mapped as usual.

    I inject the custom field mapper using spring:

    <bean id="dozerMapper" class="org.dozer.DozerBeanMapper" lazy-init="false">
        <property name="mappingFiles">
            ...
        </property>
        <property name="customFieldMapper" ref="dozerCustomFieldMapper" />
    </bean>
    <bean id="dozerCustomFieldMapper" class="my.project.MyCustomFieldMapper" />
    

    I hope this helps anyone searching for a solution for this, as I failed to find any examples when searching the Internet.

    这篇关于防止Dozer触发Hibernate延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆