为什么 Criteria API 会抛出 StackOverflow 异常?

huangapple go评论107阅读模式
英文:

Why does Criteria API throw StackOverFlow Exception?

问题

这是Cart类:

@Entity
@Table(name = "testCart_cart")
public class Cart {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cart_id", unique = true, nullable = false)
    private long id;

    @OneToMany(cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY)
    @JoinColumn(name = "cart_id")
    private List<CartItem> listOfCartItems;

    @OneToOne(mappedBy = "cart",
            fetch = FetchType.LAZY)
    private Customer customer;

    public long getId() {
        return id;
    }

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

    public List<CartItem> getListOfCartItems() {
        return listOfCartItems;
    }

    public void setListOfCartItems(List<CartItem> listOfCartItems) {
        this.listOfCartItems = listOfCartItems;
    }

    public void setCustomer(Customer customer) { this.customer = customer; }

    public Customer getCustomer() { return customer; }

    @Override
    public String toString() {
        return "Cart{" +
                "id=" + id +
                ", listOfCartItems=" + listOfCartItems +
                ", customer=" + customer +
                '}';
    }
}

这是我的Customer类:

@Entity
@Table(name = "testCart_customer")
public class Customer implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(name = "id", unique = true, nullable = false)
    private long id;

    @Column(name = "username", unique = true, nullable = false)
    private String username;

    @OneToOne(cascade = CascadeType.ALL,
            fetch = FetchType.LAZY)
    @JoinColumn(name = "cart_id")
    private Cart cart;

    public long getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Cart getCart() {
        return cart;
    }

    public void setCart(Cart cart) {
        this.cart = cart;
    }

    @Override
    public String toString() {
        return "Customer name: " + username;
    }
}

所以,我正在使用Criteria API而不是JPQL(对我来说更容易)。这是我的代码:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Cart> query = cb.createQuery(Cart.class);
Root<Customer> customer = query.from(Customer.class);
ParameterExpression<String> stringParameter = cb.parameter(String.class);
Join<Customer, Cart> carts = customer.join("cart");
query.select(carts).where(cb.equal(customer.get("username"), name));
Cart cart = entityManager.createQuery(query).getSingleResult();

return cart;

这是控制台中的错误信息:

Exception in thread "main" java.lang.StackOverflowError
	at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
	at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)
	at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
	at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)
	at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
	at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)

总共有1024次调用。尝试了来自多个来源的不同方法,还尝试使用调试器查看发生了什么,但都没有真正的解释。当调试器从 query.select... 跳到 Cart cart... 时抛出错误。

英文:

I have 2 entities with a relation of one-to-one between them: Customer and Cart. Customer is the owner of cart so a column of FK is the Customer table pointing to Cart PK.

This is Cart class:

@Entity
@Table(name = &quot;testCart_cart&quot;)
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = &quot;cart_id&quot;, unique = true, nullable = false)
private long id;
@OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY)
@JoinColumn(name = &quot;cart_id&quot;)
private List&lt;CartItem&gt; listOfCartItems;
@OneToOne(mappedBy = &quot;cart&quot;,
fetch = FetchType.LAZY)
private Customer customer;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List&lt;CartItem&gt; getListOfCartItems() {
return listOfCartItems;
}
public void setListOfCartItems(List&lt;CartItem&gt; listOfCartItems) {
this.listOfCartItems = listOfCartItems;
}
public void setCustomer(Customer customer) { this.customer = customer; }
public Customer getCustomer() { return customer; }
@Override
public String toString() {
return &quot;Cart{&quot; +
&quot;id=&quot; + id +
&quot;, listOfCartItems=&quot; + listOfCartItems +
&quot;, customer=&quot; + customer +
&#39;}&#39;;
}
}

and this is my Customer class:

@Entity
@Table(name = &quot;testCart_customer&quot;)
public class Customer implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = &quot;id&quot;, unique = true, nullable = false)
private long id;
@Column(name = &quot;username&quot;, unique = true, nullable = false)
private String username;
@OneToOne(cascade = CascadeType.ALL,
fetch = FetchType.LAZY)
@JoinColumn(name = &quot;cart_id&quot;)
private Cart cart;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Cart getCart() {
return cart;
}
public void setCart(Cart cart) {
this.cart = cart;
}
@Override
public String toString() {
return &quot;Costumer name: &quot; + username;
}
}

So, instead of JPQL (for me is easier), I am doing this with Criteria API.
This is my code:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery&lt;Cart&gt; query = cb.createQuery(Cart.class);
Root&lt;Customer&gt; customer = query.from(Customer.class);
ParameterExpression&lt;String&gt; strignParameter = cb.parameter(String.class);
Join&lt;Customer, Cart&gt; carts = customer.join(&quot;cart&quot;);
query.select(carts).where(cb.equal(customer.get(&quot;username&quot;),name));
Cart cart = entityManager.createQuery(query).getSingleResult();
return cart;

This is in console:

Exception in thread &quot;main&quot; java.lang.StackOverflowError
at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)
at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)
at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)

there are in total 1024 calls.
Tried different approaches from multiple sources plus tried to go with the debugger to see what is going on, bot nothing really explains. When the debugger jumps from query.select... to Cart cart... throws the error.

答案1

得分: 1

为何在需要购物车时以顾客作为起点。

尝试使用以下代码代替:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Cart> query = cb.createQuery(Cart.class);
Root<Cart> cart = query.from(Cart.class);
ParameterExpression<String> stringParameter = cb.parameter(String.class);
Join<Cart, Customer> customer = cart.join("customer");
query.select(cart).where(cb.equal(customer.get("username"), name));
Cart cart = entityManager.createQuery(query).getSingleResult();
英文:

Why do you start with Customer when you want Cart.

Try this instead:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery&lt;Cart&gt; query = cb.createQuery(Cart.class);
Root&lt;Cart&gt; cart = query.from(Cart.class);
ParameterExpression&lt;String&gt; strignParameter = cb.parameter(String.class);
Join&lt;Cart, Customer&gt; customer = cart.join(&quot;customer&quot;);
query.select(cart).where(cb.equal(customer.get(&quot;username&quot;), name));
Cart cart = entityManager.createQuery(query).getSingleResult();

huangapple
  • 本文由 发表于 2020年7月30日 21:53:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/63174711.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定