【问题标题】:How to filter entites scanned by LocalContainerEntityManagerFactoryBean?如何过滤 LocalContainerEntityManagerFactoryBean 扫描的实体?
【发布时间】:2015-10-14 18:28:12
【问题描述】:

我使用 Spring Boot、Spring Data JPA 和 Hibernate。

我需要通过自定义注释过滤由EntityManager 管理的实体。 LocalContainerEntityManagerFactoryBean 允许设置被扫描的包列表,但过滤器似乎在DefaultPersistenceUnitManager 中硬编码。

否则 LocalSessionFactoryBuilder(特定于 Hibernate)具有此功能(方法 setEntityTypeFilters)但不能与需要 EntityManagerFactory 的 Spring Data JPA 存储库一起使用。

如何将实体过滤应用于LocalContainerEntityManagerFactoryBean

【问题讨论】:

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


    【解决方案1】:

    我有一个类似的问题:我想“排除”一些实体,同时仍然使用LocalContainerEntityManagerFactoryBean 提供的包扫描。就我而言,我想利用 spring 使用的 @Profile(...) 注释,因为只有在特定配置文件处于活动状态时我才需要某些实体。 我通过实现PersistenceUnitPostProcessor 解决了这个问题,该PersistenceUnitPostProcessor 删除了扫描仪添加的类。它可能不是最优雅的解决方案,但它可以工作(Spring 4.1.2)。

    public class ProfileAwarePersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
    
        @Autowired
        Environment environment;
    
        /**
         * Post process the persistence unit and remove Entity classes that require a specific spring profile
         * if profile is not active.
         * 
         * @param pui The persistence unit that was put together so far.
         * @see org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor#postProcessPersistenceUnitInfo(org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo)
         */
        @Override
        public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
            // Check for null to be sure.
            if (pui.getManagedClassNames() != null) {
                Iterator<String> iterator = pui.getManagedClassNames().iterator();
                while (iterator.hasNext()) {
                    String className = iterator.next();
                    try {
                        Class<?> entityClass = Class.forName(className);
                        Profile profileAnnotation = entityClass.getAnnotation(Profile.class);
                        if (profileAnnotation != null) {
                            String[] requiredProfiles = profileAnnotation.value();
                            if (!environment.acceptsProfiles(requiredProfiles)) {
                                Logging.debug("Removing class " + className + " from persistence unit since none of the required profiles is active "
                                        + StringUtils.join(", ", requiredProfiles));
                                iterator.remove();
                            }
                        }
                    } catch (ClassNotFoundException e) {
                        // Something must have gone wrong during scanning if class is suddenly not found anymore.
                        Logging.warn("Class " + className + " not found  while post processing persistence unit.", e);
                    }
                }
            }
        }
    }
    

    可以使用任何其他注释来代替 Profile。

    【讨论】:

      【解决方案2】:

      对于 Spring Boot,只需按照 reference documentation 中的说明使用 @EntityScan

      如果 - 如该问题的 cmets 所述 - 您需要使用多个数据源,请查看 corresponding project in the Spring Data example repository

      【讨论】:

      • @EntityScan 不支持自定义过滤(仅包名称)。此外,我需要两个单独的实体管理器工厂用于两个数据库。这就是为什么我要显式配置LocalContainerEntityManagerFactoryBean
      • 那么我建议您在原始帖子中更准确地说明“过滤器”的含义。此外,如果您需要使用两个数据源,在问题中提及这一点也会有所帮助。更新了答案。
      • 感谢您的努力,抱歉我说得不准确。我需要的功能正是LocalSessionFactoryBuildersetEntityTypeFilters 中所做的。现在我使用与您提到的示例项目类似的解决方案 - 每个数据库的包中分组的实体。但是随着实体数量的增加,我想像在 Sagan 项目中一样组织它们——每个功能都打包。在我的情况下,一个包将包含来自两个数据库的实体,所以我想通过自定义注释(将由 TypeFilter 过滤)来区分它们。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-29
      • 2021-05-19
      • 1970-01-01
      • 2013-09-12
      • 2011-08-16
      • 2018-04-01
      相关资源
      最近更新 更多