我正在尝试转换此原始sql查询:
select product.* from following_relationship join product on following_relationship.following=product.owner_id where following_relationship.owner=input
在Spring Data规范中,我认为到目前为止我的问题是如何连接这些表。
这是我当前在规范中的转换:
protected Specification<Product> test(final User user){ return new Specification<Product>() { @Override public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Join<FollowingRelationship,Product> pfJoin = query.from(FollowingRelationship.class).join("following"); pfJoin.on(cb.equal(pfJoin.get("following"),"owner")); return query.where(cb.equal(pfJoin.get("following"),user)).getGroupRestriction(); } }; }
我得到这个异常:
Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessA piUsageException: org.hibernate.hql.internal.ast.InvalidWithClauseException: with clause can only reference columns in the driving table
我想补充一点,例如我是Spring框架的新手,因此这是我在Spring上的第一个应用程序,因此我对新手问题表示歉意;)
编辑:添加的实体产品,BeforeRelationShip
Entity @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "json_id_prop") public class FollowingRelationship extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "OWNER", referencedColumnName = "uuid") private User owner; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "FOLLOWING", referencedColumnName = "uuid") private User following; public User getOwner() { return owner; } public void setOwner(User owner) { this.owner = owner; } public User getFollowing() { return following; } public void setFollowing(User following) { this.following = following; } } @Entity @Table(name = "product") @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "json_id_prop") public class Product extends BaseEntity { @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "OWNER_ID", referencedColumnName = "uuid") private User owner; @NotNull private String name; @NotNull private String description; @NotNull private String price; @NotNull private String brand; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public User getOwner() { return owner; } public void setOwner(User owner) { this.owner = owner; } }
Product和FollowRelationShipShip实体没有任何明确的关系,因此我实现的联接。我要实现的是从所有用户那里获取所有产品,而另一个用户在Spring数据规范中遵循该产品。
编辑:好的,我在这里搞得一团糟,但我希望这次我更接近正确的答案。
考虑一下(id像John的1一样自动生成,等等):
INSERT INTO some_user (name) VALUES ('John'); INSERT INTO some_user (name) VALUES ('Ariel'); INSERT INTO some_user (name) VALUES ('Brian'); INSERT INTO some_user (name) VALUES ('Kelly'); INSERT INTO some_user (name) VALUES ('Tom'); INSERT INTO some_user (name) VALUES ('Sonya'); INSERT INTO product (owner_id,name) VALUES (1,'Nokia 3310'); INSERT INTO product (owner_id,name) VALUES (2,'Sony Xperia Aqua'); INSERT INTO product (owner_id,name) VALUES (3,'IPhone 4S'); INSERT INTO product (owner_id,name) VALUES (1,'Xiaomi MI5'); INSERT INTO product (owner_id,name) VALUES (3,'Samsung Galaxy S7'); INSERT INTO product (owner_id,name) VALUES (3,'Sony Xperia Z3'); INSERT INTO following_relationship (follower_id, owner_id) VALUES (4,1); INSERT INTO following_relationship (follower_id, owner_id) VALUES (5,1); INSERT INTO following_relationship (follower_id, owner_id) VALUES (4,2); INSERT INTO following_relationship (follower_id, owner_id) VALUES (6,2); INSERT INTO following_relationship (follower_id, owner_id) VALUES (6,3); INSERT INTO following_relationship (follower_id, owner_id) VALUES (1,3);
基于您提供的实体的简化版本,以及SomeUser Entity,例如:
@Entity public class FollowingRelationship { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name = "owner_id") SomeUser owner; @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name = "follower_id") SomeUser follower; ... @Entity public class Product { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @ManyToOne() @JoinColumn(name = "owner_id") private SomeUser owner; @Column private String name; ... @Entity public class SomeUser { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @Column private String name; @OneToMany(mappedBy = "owner") private Set<Product> products = new HashSet<Product>(); @OneToMany(mappedBy = "owner") private Set<FollowingRelationship> ownedRelationships = new HashSet<FollowingRelationship>(); @OneToMany(mappedBy = "follower") private Set<FollowingRelationship> followedRelationships = new HashSet<FollowingRelationship>();
我创建了像这样的规范:
public static Specification<Product> joinTest(SomeUser input) { return new Specification<Product>() { public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Join<Product,SomeUser> userProd = root.join("owner"); Join<FollowingRelationship,Product> prodRelation = userProd.join("ownedRelationships"); return cb.equal(prodRelation.get("follower"), input); } }; }
现在,当我们执行以下查询时:
SomeUser someUser = someUserRepository.findOne(Specifications.where(ProductSpecifications.userHasName("Kelly"))); List<Product> thatProducts = productRepository.findAll(Specifications.where(ProductSpecifications.joinTest(someUser))); System.out.println(thatProducts.toString());
我们得到:
[Product [id=1, name=Nokia 3310], Product [id=4, name=Xiaomi MI5], Product [id=2, name=Sony Xperia Aqua]]
在我看来,这等效于:“从另一个用户关注的所有用户那里获取所有产品”-获取Kelly正在关注的所有用户的产品。