简体   繁体   中英

How to retrieve specific rows from joined second table through JPA

I have two tables one is customer and another one is customerDepartment. Customer is having one to many relationship with customerDepartment.

I have a specific search condition where i need to search for the department name, If it equals i need to retrieve all the customer department rows including the customers.

This is what i have tried to get the results

public interface CustomerRepository extends JpaRepository<Customer,Integer>{


    @Query(value="select DISTINCT c from Customer c left join c.custDept cd where cd.deptName like %?1% ")
    Page<Customer> findByName(String name, Pageable pageable);

}

Customer

@Entity
@Table(name="customer")
public class Customer implements Serializable{


    private static final long serialVersionUID = 1L;

    @Id
    @Column(name= "customer_no",updatable = false, nullable = false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private int customerNo;

    @Column(name= "customer_name")
    private String customerName;

    @Column(name= "industry")
    private String industry;

     @JsonManagedReference
     @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, 
     fetch=FetchType.LAZY)
     private Set<CustomerDepartment> custDept;

}

CustomerDepartment:

@Entity
@Table(name = "customer_department")
public class CustomerDepartment implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "dept_id",updatable = false, nullable = false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private int depId;

    @Column(name = "dept_name")
    private String deptName;

    @Column(name = "primary_contact")
    private String primaryContact;

      @JsonBackReference
      @ManyToOne(fetch=FetchType.LAZY)
      @JoinColumn(name = "customer_no", nullable = false)
      private Customer customer;

}

When i searched for DepartmentName=it, The above JPA Query returning the below results

{
    "content": [
        {
            "customerNo": 33,
            "customerName": "Test1",
            "industry": "High-Tech",
            "country": "Australia",
            "state": "Sa-Jose",
            "city": "Sydney",
            "custDept": [
                {
                    "depId": 34,
                    "deptName": "It",
                    "primaryContact": "Banglore,Kormangala",
                },
                {
                    "depId": 35,
                    "deptName": "sales",
                    "primaryContact": "Banglore,Kormangala",

                }
            ]
        }
    ]
}   

What i am expecting is more like.

{
    "content": [
        {
            "customerNo": 33,
            "customerName": "Test1",
            "industry": "High-Tech",
            "country": "Australia",
            "state": "Sa-Jose",
            "city": "Sydney",
            "custDept": [
                {
                    "depId": 34,
                    "deptName": "It",
                    "primaryContact": "Banglore,Kormangala",
                }
            ]
        }
    ]
}   

If this is not possible in JPA, Is there any way i can do this. Thanks for the help

Yea, I thought so. I commented that "I'm thinking your query is okay but when the result is marshalled to JSON then all of the associated departments are being retrieved. You should look at your sql output and debug and check query results before marshalling to see if that is the case." I went ahead and played around with it and I was more or less correct.

The problem is that you have not fetched the custDept set with your query so when the customer is marshalled for your rest response an additional query is executed to get the values and the additional query just queries everything.

2019-05-25 14:29:35.566 DEBUG 63900 --- [nio-8080-exec-2] org.hibernate.SQL : select distinct customer0_.customer_no as customer1_0_, customer0_.customer_name as customer2_0_, customer0_.industry as industry3_0_ from customer customer0_ left outer join customer_department custdept1_ on customer0_.customer_no=custdept1_.customer_no where custdept1_.dept_name like ? limit ?

2019-05-25 14:29:35.653 DEBUG 63900 --- [nio-8080-exec-2] org.hibernate.SQL : select custdept0_.customer_no as customer4_1_0_, custdept0_.dept_id as dept_id1_1_0_, custdept0_.dept_id as dept_id1_1_1_, custdept0_.customer_no as customer4_1_1_, custdept0_.dept_name as dept_nam2_1_1_, custdept0_.primary_contact as primary_3_1_1_ from customer_department custdept0_ where custdept0_.customer_no=?

If you want only what your query supplies you need to do a fetch so the custDept the set is initialized before being marshalled. There are also other issues with your query. You should use a sql parameter :deptName and you should declare that, and you should supply a countQuery since you are returning a Page .

public interface CustomerRepository extends JpaRepository<Customer,Integer>{
    @Query(value="select DISTINCT c from Customer c left join fetch c.custDept cd where cd.deptName like %:deptName% ", 
            countQuery = "select count ( DISTINCT c ) from Customer c left join c.custDept cd where cd.deptName like %:deptName% ")
    public Page<Customer> findByName(@Param("deptName") String deptName, Pageable pageable);

Worked for me. Now only the original query is executed and the result is correct.

{
"content": [
    {
        "customerNo": 1,
        "custDept": [
            {
                "deptName": "it"
            }
        ]
    }
],

Finally note that it is better to use Integer for the @Id in your entities as per spring documentation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM