Java JPA-通过对象集合中的多个属性查找

Java JPA-通过对象集合中的多个属性查找,java,spring,jpa,spring-data-jpa,spring-data,Java,Spring,Jpa,Spring Data Jpa,Spring Data,我有一个具有以下属性的事件对象: class Event { String name; String location; LocalDateTime date; String description; } 假设我从web API获得一个事件列表: List<Events> events = getEvents(); // e.g. 5 events List events=getEvents();//e、 g.5活动 现在我想检查我的数据库中已经

我有一个具有以下属性的事件对象:

class Event {
    String name;
    String location;
    LocalDateTime date;
    String description;
}
假设我从web API获得一个事件列表:

List<Events> events = getEvents(); // e.g. 5 events
List events=getEvents();//e、 g.5活动
现在我想检查我的数据库中已经有多少这样的事件

如果名称、位置和日期等值的组合也是唯一的,则事件是唯一的

因此,基本上我想创建一个查询来实现这一点:

Optional<Event> getByNameAndLocationAndDate(String name, String location, LocalDate date);
可选的getByName和LocationAndDate(字符串名称、字符串位置、LocalDate);
但是对于一个查询中的项目列表。比如:

Optional<Event> getByNameAndLocationAndDate(List<Events> events);
可选的getByNameAndLocationAndDate(列出事件);

JPA有可能吗?

没有内置的或特别漂亮的方法来实现这一点。但您可以使用循环生成查询:

public List<Event> getByNameAndLocationAndDate(List<Event> events) {
    if (events.isEmpty()) {
        return new ArrayList<>();
    }
    final StringBuilder queryBuilder = new StringBuilder("select e from Event e where ");
    int i = 0;
    for (final Event event : events) {
        if (i > 0) {
            queryBuilder.append("or")
        } 
        queryBuilder.append(" (e.name = :name" + i);
        queryBuilder.append(" and e.location = :location" + i);
        queryBuilder.append(" and e.date = :date" + i + ") ");
        i++;
    }
    final TypedQuery<Event> query = em.createQuery(queryBuilder.toString());

    int j = 0;
    for (final Event event : events) {
        query.setParameter("name" + j, event.getName());
        query.setParameter("location" + j, event.getLocation());
        query.setParameter("date" + j, event.getDate());
    }
    return query.getResultList();
}
public List getByNameAndLocationAndDate(列出事件){
if(events.isEmpty()){
返回新的ArrayList();
}
最终StringBuilder queryBuilder=新StringBuilder(“从事件e中选择e,其中”);
int i=0;
对于(最终事件:事件){
如果(i>0){
queryBuilder.append(“或”)
} 
append(“(e.name=:name”+i);
append(“and e.location=:location”+i);
append(“and e.date=:date“+i+”);
i++;
}
final TypedQuery query=em.createQuery(queryBuilder.toString());
int j=0;
对于(最终事件:事件){
setParameter(“name”+j,event.getName());
setParameter(“location”+j,event.getLocation());
query.setParameter(“日期”+j,event.getDate());
}
返回query.getResultList();
}
就像我说的,不是很漂亮。使用标准API可能更好。此外,除非对执行速度有非常严格的要求,否则最好在列表中循环检查一个事件。这将导致对数据库运行更多的查询,但也会产生更漂亮的代码

编辑:这里是尝试使用CriteriaAPI,并没有太多使用它,所以只是通过谷歌创建的,不能保证它能正常工作

public List<Event> getByNameAndLocationAndDate(List<Event> events) {
    if (events.isEmpty()) {
        return new ArrayList<>();
    }
    final CriteriaBuilder cb = em.getCriteriaBuilder();
    final CriteriaQuery<Event> query = cb.createQuery(Event.class);
    final Root<Event> root = query.from(Event.class);

    final List<Predicate> predicates = new ArrayList<>();

    final List<Predicate> predicates = events.stream().map(event -> {
                return cb.and(cb.equal(root.get("name"), event.getName()),
                              cb.equal(root.get("location"), event.getLocation()),
                              cb.equal(root.get("date"), event.getDate()));
    }).collect(Collectors.toList());

    query.select(root).where(cb.or(predicates.toArray(new Predicate[]{})));

    return em.createQuery(query).getResultList();
}
public List getByNameAndLocationAndDate(列出事件){
if(events.isEmpty()){
返回新的ArrayList();
}
最终CriteriaBuilder cb=em.getCriteriaBuilder();
最终的CriteriaQuery=cb.createQuery(Event.class);
最终根=query.from(Event.class);
最终列表谓词=new ArrayList();
最终列表谓词=events.stream().map(事件->{
返回cb.and(cb.equal(root.get(“name”),event.getName()),
cb.equal(root.get(“location”)、event.getLocation(),
cb.equal(root.get(“date”)、event.getDate();
}).collect(Collectors.toList());
select(root).where(cb.or(predicates.toArray(newpredicate[]{}));
返回em.createQuery(query.getResultList();
}
试试看

List findbynameinandlocationanddatein(列表名称、列表位置、列表日期);
但这会返回一个列表,而不是单个事件,如果您需要验证一个事件是否不在数据库中,唯一的方法是逐个搜索, 您可以使用此功能来决定是否需要此功能


我不确定此函数是否按您的意愿运行。首先,感谢您推荐Criteria API,我相信这是正确的答案。仅供参考,
returnnewarraylist()
returncollections.emptyList()
一样更好,以避免不必要的对象实例化;另外,将
.collect(toList()).toArray(…)
替换为
.toArray(谓词[]::new)
List<Event> findByNameInAndLocationInAndDateIn(List<String> names,List<String> locations,List<Date> dates);