【问题标题】:Criteria api query in Hibernate with not existHibernate中的条件api查询不存在
【发布时间】:2012-11-25 00:01:13
【问题描述】:

我正在尝试编写查询,它会返回未分配给路线的司机列表。

我的数据库设置如下。

Route:
route_id
user_id//specified as driver

User:
user_id
role // need to select user, which is Driver role

只有路线看到用户(司机),用户(司机)看不到路线。

这是我尝试编写这样的查询。

public List<User> getUnsignedDrivers(){
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

    CriteriaQuery<User> query = criteriaBuilder.createQuery(User.class);
    Root<User> user = query.from(User.class);
    query.select(user);

    Subquery<Route> subquery = query.subquery(Route.class);
    Root<Route> subRootEntity = subquery.from(Route.class);
    Predicate correlatePredicate = criteriaBuilder.equal(subRootEntity.get("Route_.User"), user);
    subquery.where(correlatePredicate);
    query.where(criteriaBuilder.not(criteriaBuilder.exists(subquery)));

    TypedQuery<User> typedQuery = entityManager.createQuery(query);
    return typedQuery.getResultList();
}

我是 jpa 的新手,所以这就是问题所在。

更具体地说,我需要选择具有角色驱动程序的用户,这些用户未设置为任何路线

我的实体设置如下:

    @Entity
public class Route {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

@OneToOne(fetch = FetchType.EAGER, cascade = {})
@JoinColumn(name = "user_id", nullable = true)
private User driver;
.....
@Entity
public class User {

public static enum Role {
    ADMIN, MANAGER, DRIVER;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;

更新:当前查询

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

    CriteriaQuery<User> query = criteriaBuilder.createQuery(User.class);
    Root<User> user = query.from(User.class);
    Predicate predicateRole = criteriaBuilder.equal(user.get("role"), User.Role.DRIVER);
    query.where(predicateRole);
    query.select(user);


    Subquery<Route> subquery = query.subquery(Route.class);
    Root<Route> subRootEntity = subquery.from(Route.class);
    Predicate correlatePredicate = criteriaBuilder.equal(subRootEntity.get("driver"), user);
    subquery.where(correlatePredicate);
    query.where(criteriaBuilder.not(criteriaBuilder.exists(subquery)));

    TypedQuery<User> typedQuery = entityManager.createQuery(query);
    return typedQuery.getResultList();

问题依然存在

我得到了这个异常:

java.lang.IllegalStateException: No explicit selection and an implicit one cold not be determined
at org.hibernate.ejb.criteria.QueryStructure.locateImplicitSelection(QueryStructure.java:296)
at org.hibernate.ejb.criteria.QueryStructure.render(QueryStructure.java:249)
at org.hibernate.ejb.criteria.CriteriaSubqueryImpl.render(CriteriaSubqueryImpl.java:282)
at org.hibernate.ejb.criteria.predicate.ExistsPredicate.render(ExistsPredicate.java:58)
at org.hibernate.ejb.criteria.QueryStructure.render(QueryStructure.java:258)
at org.hibernate.ejb.criteria.CriteriaQueryImpl.render(CriteriaQueryImpl.java:340)
at org.hibernate.ejb.criteria.CriteriaQueryCompiler.compile(CriteriaQueryCompiler.java:217)
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:587)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy25.createQuery(Unknown Source)

在这一行抛出TypedQuery&lt;User&gt; typedQuery = entityManager.createQuery(query);

解决方法 这对我很有效。 我写了这个,因为我不能使用反向关系。

public List<User> getUnsignedDrivers(){
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

    CriteriaQuery<User> query = criteriaBuilder.createQuery(User.class);
    Root<User> user = query.from(User.class);
    Predicate predicateRole = criteriaBuilder.equal(user.get("role"), User.Role.DRIVER);
    query.where(predicateRole);
    query.select(user);

    TypedQuery<User> typedQuery = entityManager.createQuery(query);
    List<User> allDrivers = typedQuery.getResultList();
    List<User> notAssignedDrivers = new ArrayList<User>();
    List<Route> haveDriverRoutes = getRouteWithNoDrives();
    for (User driver : allDrivers){
        if (!isDriverAssigned(haveDriverRoutes,driver.getId())){
            notAssignedDrivers.add(driver);
        }
    }
    return notAssignedDrivers;
}

private boolean isDriverAssigned(List<Route> haveDriverRoutes, long driverId){
    for(Route route : haveDriverRoutes){
        if (route.getDriver().getId() == driverId){
            return true;
        }
    }
    return false;
}

@SuppressWarnings("unchecked")
public List<Route> getRouteWithNoDrives() {
    Query query = entityManager.createQuery("SELECT o FROM " + type.getSimpleName() + " o WHERE o.driver != null");
    return  query.getResultList();
}

【问题讨论】:

    标签: hibernate jpa criteria-api not-exists


    【解决方案1】:

    您在 User 实体中缺少反向 OneToOne 关系:

    @OneToOne(mappedBy="driver")
    private Route route;
    

    请参阅this link,了解如何映射 OneToOne 关系。

    你在这部分有一个错误:subRootEntity.get("Route_.User")。这不是有效的语法,并且您在 Route 实体中没有名为 User 的属性:该属性名为 driver(在阅读了您的最新编辑后)。

    您有 2 种方法来获取 Path 表达式,或者使用:

    Path<User> path = subRootEntity.get("driver");
    // in a compact way: 
    Predicate correlatePredicate = criteriaBuilder.equal(subRootEntity.get("driver"), user);
    

    或通过使用元模型:

    Path<User> path = subRootEntity.get(Route_.driver);
    // in a compact way: 
    Predicate correlatePredicate = criteriaBuilder.equal(subRootEntity.get(Route_.driver), user);
    

    您似乎混合了这两种方法。有关使用 Metamodel 的更多信息,请参阅此article

    查询的其余部分看起来正确。

    【讨论】:

    • 感谢您的帖子。是的,我在 (subRootEntity.get("Route_.User"), user) 中有错误,这是因为我不存在t have and idea, how to define correct path, for User in criteriaBuilder.equal(subRootEntity.get("Route_.User"), user); I tried to use Path&lt;User&gt; path = subRootEntity.get("user"); as you said, but it also throws me an exception, that "user" path doesnt。我怎样才能得到正确的路径?
    • subRootEntity.get("driver"); 路径有效,知道我更改为 Predicate correlatePredicate = criteriaBuilder.equal(subRootEntity.get("driver").get("id"), user.get("id")); 并引发 java.lang.IllegalStateException: No explicit selection and an implicit one cold not be determinedat org.hibernate.ejb.criteria 异常。有什么建议吗?
    • 我也试过Predicate correlatePredicate = criteriaBuilder.equal(subRootEntity.get("driver"), user);,但它抛出了java.lang.IllegalStateException: No explicit selection and an implicit one cold not be determined异常
    • 应该是逆 @OneToOne 来实现什么 im trying to do? cause i need unidirectional @OneToOne` ,因为司机不应该关心路线,只有路线应该知道司机。司机是用户。用户有 3 个角色,经理、司机和管理员,所以如果我必须使用反向 @OneToOne
    • 查询是否适用于反向关系?是的。它没有工作吗?不。您是否阅读了我在答案中添加的链接?它说这是必要的。那么,问题出在哪里?
    【解决方案2】:

    添加子查询的行应该返回一些内容。所以你应该改变: query.where(criteriaBuilder.not(criteriaBuilder.exists(subquery)));

    到:

    query.where(criteriaBuilder.not(criteriaBuilder.exists(subquery.select(subRootEntity))));
    

    【讨论】:

      猜你喜欢
      • 2012-05-01
      • 2015-01-11
      • 1970-01-01
      • 1970-01-01
      • 2011-04-26
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多