使用Spring Data预填充数据

时间:2017-12-15 16:55:00

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

我希望在保存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,并在存储库中设置root myClass。例如,像这样:

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

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

2 个答案:

答案 0 :(得分: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()

答案 1 :(得分:1)

你可以利用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的所有可能持久性,如果这对您的要求太多,则更好的其他更简单的解决方案。