Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data JPA Specification for a OneToMany Relationship

I have a problem with getting List entity Categories using Spring data JPA specifications. I need to get all Categories with their Recipes where Recipe.dateModified greater then some date. I don't know how to create my Predicate which would fill Collection<Recipe> in each category only those recipes that greater than this date.

@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;

}

In CategoryService I getting List<Category> using Specification:

@Service   
public class CategoryService {

    @Autowired
    private CategoryRepository categoryRepository;

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

}

I would write Specification like this, but this does not working.

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);
        };
    }

}
like image 811
silverhawk Avatar asked Jan 22 '26 22:01

silverhawk


1 Answers

try this one :

  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);
        };

    }

And also make sure your entities are mapped correctly:

-you are using mappedby but the association is unidirectional!

-The collection must be initialized.

-Use Date (instead of timestamp) and add @Temporal annotation!

@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;

}
like image 137
SEY_91 Avatar answered Jan 24 '26 11:01

SEY_91