Spring Data Join with Specifications

后端 未结 1 913
我在风中等你
我在风中等你 2021-02-01 17:21

I\'m trying to convert this raw sql query:

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


        
1条回答
  •  礼貌的吻别
    2021-02-01 18:15

    EDIT: Ok, I did quite a mess here, but I hope this time I'm closer to the right answer.

    Consider (id's are auto-generated like 1 for 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);
    

    Based on simplified version of entities that You provided, and SomeUser Entity like:

    @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 products = new HashSet();
    
    @OneToMany(mappedBy = "owner")
    private Set ownedRelationships = new HashSet();
    
    @OneToMany(mappedBy = "follower")
    private Set followedRelationships = new HashSet();
    

    I have created Specification like:

    public static Specification joinTest(SomeUser input) {
        return new Specification() {
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                Join userProd = root.join("owner");
                Join prodRelation = userProd.join("ownedRelationships");
                return cb.equal(prodRelation.get("follower"), input);
            }
        };
    }
    

    And now, we can execute the query with:

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

    We get:

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

    And this in My opinion is equivalent of: "get all products from all users which another user follow" - get products of all users that Kelly is following.

    0 讨论(0)
提交回复
热议问题