SQL 使用 JPA 规范的交叉连接
SQL CROSS JOIN with JPA Specification
我有一个 Spring 引导项目,它具有三个实体 类,如下所示,
@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 规范构建查询以通过 fruit.name
和 product.type
查找 items
。以下是我的搜索查询,
1. fruit = mango, type = A and fruit = apple, type = B
2. fruit = mango, type = A or fruit = apple, type = B
通过第一个查询,它需要通过 fruit.name = mango and product.type = A
和 fruit.name = apple and product.type = B
搜索所有 items
。 商品必须同时包含 A 类芒果和 B 类苹果。
第二个查询需要通过fruit.name = mango and product.type = A
或fruit.name = apple and product.type = B
搜索所有items
。 如果任何商品包含 A 类芒果或 B 类苹果,则它应该 return 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;
};
}
我的问题是 and query
不工作,所以它没有给我结果。那么有人可以帮我解决这个问题吗?我在这里做错了什么?
这是 JPA 生成的 AND
查询,
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 生成的 OR
查询,
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 ?
AND 将不起作用,因为您正在对与其他检查相同的 product/fruit 执行过滤器检查。产品的水果不能既是苹果又是芒果。解决方案是手动创建两个单独的显式连接
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;
};
}
这更多地转化为给我一个既有苹果产品又有芒果产品的项目。
我有一个 Spring 引导项目,它具有三个实体 类,如下所示,
@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 规范构建查询以通过 fruit.name
和 product.type
查找 items
。以下是我的搜索查询,
1. fruit = mango, type = A and fruit = apple, type = B
2. fruit = mango, type = A or fruit = apple, type = B
通过第一个查询,它需要通过 fruit.name = mango and product.type = A
和 fruit.name = apple and product.type = B
搜索所有 items
。 商品必须同时包含 A 类芒果和 B 类苹果。
第二个查询需要通过fruit.name = mango and product.type = A
或fruit.name = apple and product.type = B
搜索所有items
。 如果任何商品包含 A 类芒果或 B 类苹果,则它应该 return 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;
};
}
我的问题是 and query
不工作,所以它没有给我结果。那么有人可以帮我解决这个问题吗?我在这里做错了什么?
这是 JPA 生成的 AND
查询,
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 生成的 OR
查询,
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 ?
AND 将不起作用,因为您正在对与其他检查相同的 product/fruit 执行过滤器检查。产品的水果不能既是苹果又是芒果。解决方案是手动创建两个单独的显式连接
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;
};
}
这更多地转化为给我一个既有苹果产品又有芒果产品的项目。