J'essaie de convertir cette requête SQL brute:
select product.* from following_relationship
join product on following_relationship.following=product.owner_id
where following_relationship.owner=input
Dans les spécifications Spring Data, je pense que mon problème jusqu'à présent est de rejoindre ces tables.
Voici ma conversion actuelle dans les spécifications:
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();
}
};
}
Et je reçois cette exception:
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
Je voudrais ajouter que je suis nouveau au framework Spring, par exemple, c'est ma première application sur le printemps, donc mes excuses pour la question du débutant;)
Edit: entités ajoutées Product, FollowRelationShip
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;
}
}
Les entités Product et FollowRelationShip n'ont aucune relation explicite, d'où la jointure sur mon implémentation. Ce que je veux réaliser, c'est obtenir tous les produits de tous les utilisateurs qu'un autre utilisateur suit dans les spécifications des données de Spring.
EDIT: Ok, j'ai fait pas mal de bazar ici, mais j'espère que cette fois je suis plus proche de la bonne réponse.
Considérez (les identifiants sont générés automatiquement comme 1 pour John, etc.):
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);
Basé sur une version simplifiée des entités que vous avez fournies, et une entité SomeUser comme:
@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>();
J'ai créé des spécifications comme:
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);
}
};
}
Et maintenant, quand nous faisons la requête comme:
SomeUser someUser = someUserRepository.findOne(Specifications.where(ProductSpecifications.userHasName("Kelly")));
List<Product> thatProducts = productRepository.findAll(Specifications.where(ProductSpecifications.joinTest(someUser)));
System.out.println(thatProducts.toString());
On a:
[Product [id=1, name=Nokia 3310], Product [id=4, name=Xiaomi MI5], Product [id=2, name=Sony Xperia Aqua]]
Et cela, à mon avis, équivaut à: "obtenir tous les produits de tous les utilisateurs qu'un autre utilisateur suit" - obtenir les produits de tous les utilisateurs que Kelly suit.