SQL CROSS JOIN 与 JPA 规范

发布于 2025-01-19 05:21:16 字数 3325 浏览 0 评论 0原文

我有一个Spring Boot项目,该项目具有以下三个实体类,

@Entity
@Table("item")
public class Item extends SomeParent {

     @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "item")
     @JsonManagedReference("product-s")
     Set<Product> products;
}

@Entity
@Table(name = "product")
public class Product extends SomeParent {

     @ManyToOne
     @JoinColumn(name = "item_id", nullable = false)
     @JsonBackReference("product-s")
     private Item item;

     @ManyToOne
     @JoinColumn(name = "fruit_id", nullable = false)
     private Fruit fruit;

     private String type;
}

@Entity
@Table(name = "fruit")
public class Fruit extends SomeParent {

     private String name;

     private Integer qty;
}

我正在使用JPA规范来构建查询以查找项目 by fruit.name.nameproduct .type。以下是我的搜索查询,

1. fruit = mango, type = A and fruit = apple, type = B 
2. fruit = mango, type = A or fruit = apple, type = B 

通过第一个查询,它需要搜索所有项目 by fruit.name = mango and product.type = a fruit.name =苹果和product.type = b项目必须具有类别的芒果,而苹果则具有类别。

通过第二查询,需要搜索所有项目 by fruit.name = name =芒果和产品。 如果任何项目都有具有类别的芒果或具有B类的Apple,则应返回item

public Specification<Item> search() {
    return (root, query, criteriaBuilder) -> {
       SetJoin<Item, Product> productJoin = root.joinSet("products", JoinType.LEFT);

       if (isAndQuery) { 
          criteriaBuilder.and(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "mango"), 
                    criteriaBuilder.equal(productJoin.get("type"), "A")));
          criteriaBuilder.and(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "apple"), 
                    criteriaBuilder.equal(productJoin.get("type"), "B")));
       } else {
          criteriaBuilder.or(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "mango"),
                    criteriaBuilder.equal(productJoin.get("type"), "A")));
          criteriaBuilder.or(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "apple"),
                    criteriaBuilder.equal(productJoin.get("type"), "B")));
       }

       return criteriaBuilder;
    };
}

我的问题是,并且查询不起作用,因此它没有给我结果。那么有人可以帮助我解决这个问题吗?我在这里做错了什么?

这是JPA生成的查询,

select * from item item
left outer join product product on item.id=product.item_id 
cross join fruit fruit
where product.fruit_id=fruit.id
and ((fruit.name='mango')
and product.type='A'
and (fruit.name='apple')
and product.type='B')
order by item.id asc limit ?

这是JPA生成的查询,

select * from item item 
left outer join product product on item.id=product.item_id 
cross join fruit fruit
where product.fruit_id=fruit.id
and ((fruit.name='mango')
and product.type='A'
or (fruit.name='apple')
and product.type='B')
and 1=1
order by
item.id asc limit ?

I have a Spring Boot project which has three entity classes like the following,

@Entity
@Table("item")
public class Item extends SomeParent {

     @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "item")
     @JsonManagedReference("product-s")
     Set<Product> products;
}

@Entity
@Table(name = "product")
public class Product extends SomeParent {

     @ManyToOne
     @JoinColumn(name = "item_id", nullable = false)
     @JsonBackReference("product-s")
     private Item item;

     @ManyToOne
     @JoinColumn(name = "fruit_id", nullable = false)
     private Fruit fruit;

     private String type;
}

@Entity
@Table(name = "fruit")
public class Fruit extends SomeParent {

     private String name;

     private Integer qty;
}

I am using JPA Specification to build a query to find items by fruit.name and product.type. Following are my search queries,

1. fruit = mango, type = A and fruit = apple, type = B 
2. fruit = mango, type = A or fruit = apple, type = B 

By the 1st query it needs to search all the items by fruit.name = mango and product.type = A and fruit.name = apple and product.type = B. Item must have both mango with A category and apple with B category.

By the 2nd query it needs to search all the items by fruit.name = mango and product.type = A or fruit.name = apple and product.type = B. If any item has mango with A category or apple with B category then it should return the item

public Specification<Item> search() {
    return (root, query, criteriaBuilder) -> {
       SetJoin<Item, Product> productJoin = root.joinSet("products", JoinType.LEFT);

       if (isAndQuery) { 
          criteriaBuilder.and(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "mango"), 
                    criteriaBuilder.equal(productJoin.get("type"), "A")));
          criteriaBuilder.and(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "apple"), 
                    criteriaBuilder.equal(productJoin.get("type"), "B")));
       } else {
          criteriaBuilder.or(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "mango"),
                    criteriaBuilder.equal(productJoin.get("type"), "A")));
          criteriaBuilder.or(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "apple"),
                    criteriaBuilder.equal(productJoin.get("type"), "B")));
       }

       return criteriaBuilder;
    };
}

My issue is and query is not working, so it is not giving me the results. So can anybody help me to resolve this issue? What is I am doing wrong here?

This is the JPA generated AND query,

select * from item item
left outer join product product on item.id=product.item_id 
cross join fruit fruit
where product.fruit_id=fruit.id
and ((fruit.name='mango')
and product.type='A'
and (fruit.name='apple')
and product.type='B')
order by item.id asc limit ?

This is the JPA generated OR query,

select * from item item 
left outer join product product on item.id=product.item_id 
cross join fruit fruit
where product.fruit_id=fruit.id
and ((fruit.name='mango')
and product.type='A'
or (fruit.name='apple')
and product.type='B')
and 1=1
order by
item.id asc limit ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

狂之美人 2025-01-26 05:21:16

AND 不起作用,因为您正在对与其他检查相同的产品/水果执行过滤器检查。产品的水果不能同时是苹果和芒果。解决方案是手动创建两个单独的显式连接,

public Specification<Item> search() {
   return (root, query, criteriaBuilder) -> {
       Predicate returnPredicate;
       SetJoin<Item, Product> productJoin = root.joinSet("products", JoinType.LEFT);

       if (isAndQuery) { 
          SetJoin<Item, Product> productJoin2 = root.joinSet("products", JoinType.LEFT);
          returnPredicate = criteriaBuilder.and(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "mango"), 
                    criteriaBuilder.equal(productJoin.get("type"), "A"))),
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin2.get("fruit").get("name"), "apple"), 
                    criteriaBuilder.equal(productJoin2.get("type"), "B")));
       } else {
          returnPredicate = criteriaBuilder.or(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "mango"),
                    criteriaBuilder.equal(productJoin.get("type"), "A"))),
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "apple"),
                    criteriaBuilder.equal(productJoin.get("type"), "B")));
       }

       return returnPredicate;
   };
}

这更多地翻译为给我一个项目,该项目既包含带有 Apple 的产品,又包含带有芒果的单独产品。

AND won't work because you are performing the filter check on the same product/fruit as the other checks. A product's fruit can't be both an apple and a mango. The solution is to manually create two separate, explicit joins

public Specification<Item> search() {
   return (root, query, criteriaBuilder) -> {
       Predicate returnPredicate;
       SetJoin<Item, Product> productJoin = root.joinSet("products", JoinType.LEFT);

       if (isAndQuery) { 
          SetJoin<Item, Product> productJoin2 = root.joinSet("products", JoinType.LEFT);
          returnPredicate = criteriaBuilder.and(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "mango"), 
                    criteriaBuilder.equal(productJoin.get("type"), "A"))),
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin2.get("fruit").get("name"), "apple"), 
                    criteriaBuilder.equal(productJoin2.get("type"), "B")));
       } else {
          returnPredicate = criteriaBuilder.or(
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "mango"),
                    criteriaBuilder.equal(productJoin.get("type"), "A"))),
               criteriaBuilder.and(
                    criteriaBuilder.equal(productJoin.get("fruit").get("name"), "apple"),
                    criteriaBuilder.equal(productJoin.get("type"), "B")));
       }

       return returnPredicate;
   };
}

This translates more into give me the Item that has both a product with an Apple and a separate product with a mango.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文