java - 如何为多个级别创建 Hibernate Criteria

标签 java hibernate hibernate-criteria

我正在尝试使用 hibernate criteria API 设计一个查询。目标是获取以 java.util.Set 形式存储在第三级的经过过滤的项目列表,这些项目与特定值匹配。此外,应该在最外层过滤列表以获取另一个特定值。下面是形成多级关系的模型类:

卖家.java

@Entity
@Table(name="seller")
public class Seller {
    private Integer id;
    private Set<Store> stores;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id", unique=true, nullable=false)
    public Integer getId(){
        return id;
    }
    public void setId(Integer id){
        this.id = id;
    }

    @ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinTable(name="seller_store",
        joinColumns={@JoinColumn(name="sellertid")},
        inverseJoinColumns={@JoinColumn(name="storeid", referencedColumnName="id")})
    @ForeignKey(name="fk_sellerid_seller_store", inverseName="fk_storeid_seller_store")
    public Set<Store> getStores() {
        return stores;
    }
    public void setStores(Set<Store> stores) {
        this.stores = stores;
    }
}

商店.java

@Entity
@Table(name="store")
public class Store {
    private Integer id;
    private Stock stock;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id", unique=true, nullable=false)
    public Integer getId(){
        return id;
    }
    public void setId(Integer id){
        this.id = id;
    }

    @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER, orphanRemoval=true)
    @JoinColumn(name="stockid", referencedColumnName="id")
    @ForeignKey(name="fk_stockid_store")
    public Stock getStock() {
        return stock;
    }
    public void setStock(Stock stock) {
        this.stock = stock;
    }
}

Stock.java

@Entity
@Table(name="stock")
public class Stock {
    private Integer id;
    private Set<Item> stockItems;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id", unique=true, nullable=false)
    public Integer getId(){
        return id;
    }
    public void setId(Integer id){
        this.id = id;
    }

    @ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinTable(name="stock_stockitem",
            joinColumns={@JoinColumn(name="stockid")},
            inverseJoinColumns={@JoinColumn(name="stockitemid")})
    @ForeignKey(name="fk_stockid_stock", inverseName="fk_stockitemid_stock")
    public Set<Item> getStockItems() {
        return stockItems;
    }
    public void setStockItems(Set<Item> stockItems) {
        this.stockItems = stockItems;
    }

}

项目.java

@Entity
@Table(name="item")
public class Item {
    private Integer id;
    private String name;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id", unique=true, nullable=false)
    public Integer getId(){
        return id;
    }
    public void setId(Integer id){
        this.id = id;
    }

    @Column(name="name", unique=true)
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
}

现在我需要获取一个特定的 Stock 对象,其中包含具有特定 id 的 Item 以及具有特定 id 的 Seller 。我可以通过 id 获取顶级 Seller 对象来轻松地做到这一点,但这会给我的代码带来负担,需要使用多个 for 循环手动过滤生成 Stock 列表,这绝对是这不是一个好主意。任何有关映射和/或标准逻辑的建议和指南将不胜感激。 提前致谢!

最佳答案

第一步应该是更改 Store 实体以支持 toMany 卖家,然后我将开始编写 jpql 查询

SELECT * FROM stock s 
JOIN stock.items si 
JOIN stock.store.sellers sss
WHERE si.id IN(:itemIds) 
AND sss.id IN(:sellerIds)

第二步是按照条件查询方式重写此查询

CriteriaQuery<Stock> cq = cb.createQuery(Stock.class);
Metamodel m = em.getMetamodel();
EntityType<Stock> Stock_ = m.entity(Stock.class);
Root<Stock> stock = cq.from(Stock.class);
Join<Stock, Item> items = stock.join(Stock_.items);
Join<Stock, Store> store = stock.join(Stock_.store);
Join<Store, Seller> sellers = store.join(Store_.sellers);
cq.where(cb.in(items.get(Item_.id), Arrays.asList(1, 2, 3, 4))
    .and(cb.in(sellers.get(Seller_.id), Arrays.asList(1, 2, 3, 4));

我还没有测试过这个查询,所以我不确定它是否会起作用。不过,这就是想法。

更新

对于 Hibernate Criteria Query,应用与连接类似的概念,但在本例中创建子条件:

List stocks = sess.createCriteria(Stock.class)
  .createCriteria("items")
    .add( Restrictions.in("id", {1, 2, 3, 4, 5}) )
  .createCriteria("store")
    .createCriteria("sellers")
      .add( Restrictions.like("id", {1, 2, 3, 4, 5}) )
  .list();

或使用别名:

List stocks = sess.createCriteria(Cat.class)
  .createAlias("items", "si")
  .createAlias("store.sellers", "sss")
    .add( Restrictions.in("si.id", {1, 2, 3, 4, 5}) )
    .add( Restrictions.in("sss.id", {1, 2, 3, 4, 5}) )
  .list();

我再次不确定这些查询是否有效。

最后的建议是,您应该避免使用供应商特定的工具。 JPA 标准查询是标准。这意味着其他供应商也在使用它。例如,如果您使用 JPA 标准而不是 Hibernate Criteria,则可以在 Hibernate 和 EclipseLink 之间切换而不会出现很多问题,因为两个供应商都应该遵循该标准(不是 100%,而是高度)。

关于java - 如何为多个级别创建 Hibernate Criteria,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29048663/

相关文章:

java - 如何用 Java 确定 youtube 上的视频文件大小?

java - Android访问远程mysql数据库

java - 如何检查 netbeans 中的编译器和运行时?

c# - 在 C# 中访问可空值的最佳方式

java - 如果可能,将 jFrame 输出到第二台显示器

hibernate - 为类 classname 提供了错误类型的 id 预期为 : class java. lang.Integer,得到了类 java.lang.String

java - 如何使用 Hibernate 正确删除复杂对象?

java - maven无法添加库

java - hibernate : Criteria ignoring fetchSize parameter and fetching more rows than asked

Java Hibernate暂时忽略带有条件的@ManyToOne注释