【问题标题】:Prepopulate data using Spring Data使用 Spring Data 预填充数据
【发布时间】:2017-12-19 17:38:35
【问题描述】:

我希望能够在持久化 spring 数据之前使用一些更复杂的保存逻辑。

我有这个 JpaRepository :

public interface MyClassRepository extends JpaRepository<MyClass, Long> {
    @Query("from com.package.MyClass as myClass where myClass.parent is null");
    MyClass getRootMyClass();
    ...
}

还有这个实体:

@Entity
@Table("MY_CLASS")
public class MyClass {
    @ManyToOne
    @JoinColumn("parent_id")
    MyClass parent;
}

我希望能够检查父属性是否为 null,然后在存储库中设置根 myClass。例如,像这样:

if(myClass.getParent() == null) {
    myClass.setParent(getRootMyClass());  
}

我无法在实体中使用@PrePersist 挂钩,因为它不知道存储库。我不能在存储库中这样做,因为它是一个接口而不是一个类。放在哪里最好?

【问题讨论】:

  • 你的意思是,你想在你的仓库中保存一个对象之前检查if (parent!=null)
  • “设置根 myClass”是什么意思。执行 getRootMyClass() 后,您通过设置 parent 属性来保存返回值?

标签: java spring spring-data spring-data-jpa


【解决方案1】:

如果你使用的是JDK8,可以在MyClassRepository中添加如下方法:

public interface MyClassRepository extends JpaRepository<MyClass, Long> {

    @Query("from com.package.MyClass as myClass where myClass.parent is null")
    MyClass getRootMyClass();

    default void checkSave(MyClass myClass) {
        if (myClass.getParent() == null) {
            myClass.setParent(getRootMyClass());
        }
        save(myClass);
    }
}

然后,你应该调用 checkSave() 而不是 save()

【讨论】:

    【解决方案2】:

    你可以利用Hibernate的PreInsertEventListener,你可以为Hibernate的每一个prePersist操作注册这样一个拦截器;

    @Component
    public class MyEventListener implements PreInsertEventListener {
    
        @Autowired
        private EntityManagerFactory entityManagerFactory;
    
        @Autowired
        private MyClassRepository myClassRepository;
    
        @PostConstruct
        private void init() {
            SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
            EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
            registry.getEventListenerGroup(EventType.PRE_INSERT).appendListener(this);
        }
    
        @Override
        public boolean onPreInsert(PreInsertEvent preInsertEvent) {
            if (MyClass.class.equals(preInsertEvent.getEntity().getClass())) {
                MyClass entity = (MyClass) preInsertEvent.getEntity();
                if(myClass.getParent() == null) {
                    myClass.setParent(myClassRepository.getRootMyClass());  
                }
            }
            return false;
        }
    }
    

    这种方法背后的想法是,Hibernate 中的所有持久事件都会被拦截,例如,如果有一些级联插入,这仍然会触发。因此,此解决方案涵盖了MyClass 的所有可能的持久性,如果这对您的要求来说太多了,其他更简单的解决方案是更可取的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-15
      • 2013-06-08
      • 2019-03-22
      • 2012-05-05
      • 2017-09-06
      • 2012-04-28
      • 1970-01-01
      • 2016-06-19
      相关资源
      最近更新 更多