OneToMany关系的Spring Data JPA规范

时间:2016-09-01 13:18:16

标签: java spring hibernate spring-data-jpa criteria-api

我使用Spring数据JPA规范获取List实体类别时遇到问题。我需要使用他们的食谱获得所有类别Recipe.dateModified大于某个日期。我不知道如何创建我的Predicate,它会在每个类别中填充Collection<Recipe>只有那些大于此日期的食谱。

@Entity    
public class Category {

    private int id;
    private String name;

    @OneToMany(mappedBy = "categories")
    private Collection<Recipe> recipes;
}

@Entity
public class Recipe {

    private int id;
    private String name;

    private Timestamp dateModified;

}

CategoryService我使用规范获取List<Category>

@Service   
public class CategoryService {

    @Autowired
    private CategoryRepository categoryRepository;

    public List<Category> findAll(Date date) {
        return categoryRepository.findAll(where(byDateModified(date)));
    }

}

我会像这样编写规范,但这不起作用。

public class RecipeSpec {

    public static Specification<Category> byDateModified(Date date) {
        return (root, query, builder) -> {
            final Join<Category, Recipe> recipe = root.join(Category_.recipes, JoinType.LEFT);
            return builder.greaterThan(recipe.get(Recipe_.dateModified), date);
        };
    }

}

2 个答案:

答案 0 :(得分:0)

在CategoryRepository Implementation类中,添加此方法

public Category findAll(Date dateModified) {
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Category> query = builder.createQuery(Category.class);
    Root<Category> category = query.from(Category.class);

    ParameterExpression<Date> dateParam = builder.parameter(Date.class);
    query.select(category).where(builder.greaterThan(category.get(Category_.recipes).get(Recipe_.dateModified), dateParam));

    return em.createQuery(query)
            .setParameter(dateParam, dateModified)
            .getSingleResult();
}

MetaModel类用于上面的代码中。如果没有生成元模型类,则在pom文件中添加此插件以自动生成元模型类..

<plugin>
   <groupId>org.bsc.maven</groupId>
   <artifactId>maven-processor-plugin</artifactId>
   <version>2.2.4</version>
   <executions>
     <execution>
       <id>process</id>
       <goals>
         <goal>process</goal>
       </goals>
       <phase>generate-sources</phase>
       <configuration>
         <processors>
           <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
         </processors>
       </configuration>
     </execution>
   </executions>
   <dependencies>
     <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-jpamodelgen</artifactId>
       <version>5.2.2.Final</version>
     </dependency>
   </dependencies>
 </plugin>

答案 1 :(得分:0)

试试这个:

  public class RecipeSpec {

     public static Specification<Category> byDateModified(Date date) {
       return new Specification<Category>() {

        public Predicate toPredicate(Root<Category> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
            List<Predicate> predicates = new ArrayList<Predicate>();

            final Path<Collection<Recipe>> recipes = root.get(Recipe_.recipes);
            final Path<Date> dateModified = recipes.get(Recipe_.dateModified);
         return builder.greaterThan(dateModified, date);
        };

    }

并确保您的实体正确映射:

- 你正在使用mappedby,但关联是单向的!

- 必须初始化集合。

- 使用日期(而不是时间戳)并添加@Temporal注释!

@Entity    
public class Category {

    private int id;
    private String name;

    //@OneToMany(mappedBy = "categories") 
    @OneToMany
    @JoinColumn(name="categoryId")
    private Collection<Recipe> recipes = new ArrayList<Recipe>();
}

@Entity
public class Recipe {

    private int id;
    private String name;
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateModified;

}