2016-07-03 36 views
5

sto cercando di convertire questa query SQL prime:primavera dati registrazione con specifiche

select product.* from following_relationship 
join product on following_relationship.following=product.owner_id 
where following_relationship.owner=input 

Into specifiche primavera dati, penso che il mio problema finora è per unirsi quei tavoli.

Ecco il mio attuale conversione in Specification:

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(); 

     } 
    }; 
} 

e sto ottenendo questa eccezione:

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 

mi piacerebbe aggiungere che io sono nuovo a framework Spring per esempio questo è la mia prima domanda in primavera, quindi le mie scuse per la domanda newbie;)

Modifica: aggiunto entità Prodotto, FollowingRelationShip

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; 
    } 


} 

Le entità Product e FollowingRelationShip non hanno alcuna relazione esplicita, quindi il join sulla mia implementazione about.What voglio ottenere è ottenere tutti i prodotti da tutti gli utenti che un altro utente segue in Spring data Specifications.

+0

dovrebbe 'pfJoin.on (cb.equal (pfJoin.get (" following ")," owner "));' be 'pfJoin.on (cb.equal (pfJoin.get (" following ")," owner_id "));'? – Galz

+1

Questo è il caso in cui un pacchetto di terze parti si intrometta.. –

+0

@Galz yes, owner_id è il nome della colonna unita che ha riferimento al campo uuid proprietario (che è anche l'ID dell'entità). Btw ho provato già con owner_id e proprietario ma nessuno funziona – murielK

risposta

9

EDIT: Ok, ho fatto un bel casino qui, ma spero che questa volta sia più vicino alla risposta giusta.

considerare (id sono generati automaticamente come 1 per John, ecc):

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); 

Sulla base di versione semplificata di entità che ci hai fornito, e QualcheUtente Entità come:

@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>(); 

ho Specificazione creata come:

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); 
     } 
    }; 
} 

E ora, quando facciamo la query come:

SomeUser someUser = someUserRepository.findOne(Specifications.where(ProductSpecifications.userHasName("Kelly"))); 
List<Product> thatProducts = productRepository.findAll(Specifications.where(ProductSpecifications.joinTest(someUser))); 
System.out.println(thatProducts.toString()); 

otteniamo:

[Product [id=1, name=Nokia 3310], Product [id=4, name=Xiaomi MI5], Product [id=2, name=Sony Xperia Aqua]] 

E questo a mio parere è equivalente di: "ottenere tutti i prodotti da tutti gli utenti che seguono un altro utente" - ottenere prodotti di tutti gli utenti che Kelly sta seguendo.

+0

Grazie, lo farò non appena torno a casa. Si prega di – murielK

+0

Prodotto e FollowingRelationship non hanno alcuna relazione l'unica cosa che hanno in comune sono utente in cui così ogni prodotto ha il suo proprietario (utente) dove FollowingRelationship hanno il campo seguente e campo follower (che sono tutti Tipo di utente o entità). Quindi sto cercando di ottenere tutti i prodotti da tutti gli utenti che altri utenti specifici stanno seguendo. – murielK

+0

Questo è il motivo per cui ho bisogno di aderire all'entità Prodotto su FollowingRelationship Entity dove FollowingRelationship.following = product.owner – murielK