【问题标题】:JPA JPQL query, where object1 = object2JPA JPQL 查询,其中 object1 = object2
【发布时间】:2013-11-13 21:15:00
【问题描述】:

Query1(工作正常!!!):

em.createQuery(
            "SELECT r FROM Route r WHERE r.start.x = :x"
            , Route.class).setParameter("x", start.getX())

Query2(我真的很喜欢这个工作!):

   em.createQuery(
            "SELECT r FROM Route r WHERE r.start = :x"
            , Route.class).setParameter("x", start)
            .setMaxResults(20)

抛出: TransientObjectException: 对象引用了一个未保存的瞬态实例 - 在刷新之前保存瞬态实例

路由实体:

 @Entity
@XmlRootElement(name="route")

@XmlAccessorType(XmlAccessType.NONE)
public class Route {
private Long id;
private User user;
private Location start;
private Location finish;

public Route() {
}

@Id
@GeneratedValue
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

@ManyToOne
@JoinColumn
public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

@OneToOne(cascade=CascadeType.PERSIST)
public Location getStart() {
    return start;
}

public void setStart(Location start) {
    this.start = start;
}

@OneToOne(cascade=CascadeType.PERSIST)
public Location getFinish() {
    return finish;
}

public void setFinish(Location finish) {
    this.finish = finish;
}

}

地点:

@Entity
public class Location {

@Id
@GeneratedValue
private Long id;

private double x;

private double y;

public Location() {
}

public Location(double x, double y) {
    this.x = x;
    this.y = y;
}

@XmlTransient
public double getX() {
    return x;
}

public void setX(double x) {
    this.x = x;
}

public double getY() {
    return y;
}

public void setY(double y) {
    this.y = y;
}

public boolean equals(Object o) {
    if ((o instanceof Location)
            && (((Location)o).getX() == this.x)
            && (((Location)o).getY() == this.y))
    {
        return true;
    }
    else return false;
}

}

【问题讨论】:

  • start 变量是什么?为什么不调用第二个例子中的getX()方法呢?
  • 'start' 是从 HTTP POST 数据接收到的位置类的实例......例如。与 Location start = new Location("1.0","1.0"); 相同...我没有使用 getx(),因为我希望能够测试复杂对象的相等性 ...

标签: jakarta-ee jpa java-ee-6 jpql


【解决方案1】:

异常与查询本身没有太大关系。

它被抛出是因为在执行查询之前,Hibernate 会刷新尚未刷新的更改。并且不能这样做,因为......一个对象引用了一个未保存的瞬态实例。因此,请确保在执行查询之前保存瞬态实例。

【讨论】:

  • 好吧,我可以看到 Route 并且它的 start 属性(以及所有其他相关实体)在运行查询之前被持久化到数据库中......所以我看不出可能是什么短暂的实例。
  • 使用调试器单步执行代码,并尝试跟踪所有附加到托管实体但在执行查询之前未持久化的实体。
  • 在运行查询之前,我只保留了一个实体:“用户”,用户有 1 个路由,路由有一个开始和结束位置。一旦我调用 em.getTransaction().commit();我可以在数据库中看到所有这些。如果我尝试调用 em.flush,jboss 会告诉我没有活动的事务。所以我可以调用 em.close()。然后创建新的 EntityManager 来运行有问题的查询。我怀疑错误可能是由于 "start"(Location class) 引用的位置,它是从 HTTP POST 数据接收的,并且 id = null。但我觉得这个理论有点牵强。
  • 我已经手动设置了从 POST 接收到的对象的 ID,start.setId(7777l) 并且 抑制了错误。但是,两个对象之间的相等性 尚未正确测试。如果我建立一个查询SELECT r FROM Route r,然后转到result.get(0).getStart().equals(start);,它将返回true。但是List<Route> routes = em.createQuery( "SELECT r FROM Route r WHERE r.start = :start").setParameter("start", start).getResultList(); .. 将返回 empty List :(
  • Java 代码使用 equals() 方法比较对象。查询搜索与作为参数传递的起始对象的 ID 相同的起始 ID 的路由。
【解决方案2】:

当通过构造函数实例化的类与从数据库中读取的同一类的相同对象进行比较时,引发了 TransientObjectException。由于类路由被注释为@Entity,查询认为第一个对象是瞬态的(因为它没有设置@id 字段)。

【讨论】:

    猜你喜欢
    • 2014-05-09
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    • 2013-10-14
    • 2015-01-26
    • 2018-01-06
    • 2018-01-21
    • 2017-11-30
    相关资源
    最近更新 更多