How to implement Server-side processing of DataTables with JDBC so that it paginates?

混江龙づ霸主 提交于 2020-01-25 06:56:05

问题


I have a Spring Boot app with DataTables server-side processing and Oracle database. Actually, I started with implementing one of the tutorials. It worked. The tutorial uses JPA. I want to implement the same using JDBC. I made all the corresponding classes, the repository, the new model with same filds but without jpa. But when I tried to fetch the data, it allowed me to get only the first page without a chance to get to the second page. Below I will post the extracts of the original and added code. So, the original tutorial used these classes:

@Entity
@Table(name = "MYUSERS")
public class User {

    @Id
    @Column(name = "USER_ID")
    private Long id;

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

    @Column(name = "SALARY")
    private String salary;

...getters and setters
}

And

@Entity
public class UserModel {

    @Id
    private Long id;
    private String name;
    private String salary;

    private Integer totalRecords;

    @Transient
    private Integer rn;

...getters and setters
}

And I substituted these two classes with one like this:

public class NewUser {

    private Long id;
    private String name;
    private String salary;
    private Integer totalRecords;
    private Integer rn;

...getters and setters
}

The table itself has only 3 fields: id, name and salary, the other 2 fields are created and filled later. The repositiry the original Author has for the user looks like this:

public interface UserRepository extends JpaRepository<User, Long> {

    @Query(value = "SELECT * FROM MYUSERS", nativeQuery = true)
    List<User> findAllByUsernames(List<String> listOfUsernames);
}

My own repository looks like this:

@Repository
public class NewUserRepoImpl extends JdbcDaoSupport implements NewUserRepo {

    private static final String SELECT_ALL_SQL = "SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS";

    private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    private final JdbcTemplate jdbctemplate;

    public NewUserRepoImpl(NamedParameterJdbcTemplate namedParameterJdbcTemplate, JdbcTemplate jdbctemplate, DataSource dataSource) {
        this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
        this.jdbctemplate = jdbctemplate;
        setDataSource(dataSource);
    }

    @Override
    public List<NewUser> findAll(PaginationCriteria pagination) {
        try {
            String paginatedQuery = AppUtil.buildPaginatedQueryForOracle(SELECT_ALL_SQL, pagination);
            return jdbctemplate.query(paginatedQuery, newUserRowMapper());
        } catch (DataAccessException e) {
            throw new EntityNotFoundException("No Entities Found");
        }
    }

    @Bean
    public RowMapper<NewUser> newUserRowMapper() {
        return (rs, i) -> {
            final NewUser newUser = new NewUser();
            newUser.setId(rs.getLong("ID"));
            newUser.setName(rs.getString("NAME"));
            newUser.setSalary(rs.getString("SALARY"));
            newUser.setTotalRecords(rs.getInt("TOTAL_RECORDS"));
            newUser.setTotalRecords(rs.getInt("RN"));
            return newUser;
        };
    }
}

the buildPaginatedQueryForOracle thing transforms my Query and allows it to get the totalRecords and rn. Below I will post the output of it both for the orifinal and my queries (they are the same, I checked).

So, the main part, the controller. I left the old and new pieces in it for now for debug purposes and just returning one of the results:

@RequestMapping(value="/users/paginated/orcl", method=RequestMethod.GET)
    @ResponseBody
    public String listUsersPaginatedForOracle(HttpServletRequest request, HttpServletResponse response, Model model) {

        DataTableRequest<User> dataTableInRQ = new DataTableRequest<User>(request);
        System.out.println(new Gson().toJson(dataTableInRQ));
        DataTableRequest<NewUser> dataTableInRQNew = new DataTableRequest<NewUser>(request);
        System.out.println(new Gson().toJson(dataTableInRQNew));
        PaginationCriteria pagination = dataTableInRQ.getPaginationRequest();
        System.out.println(new Gson().toJson(pagination));
        PaginationCriteria paginationNew = dataTableInRQNew.getPaginationRequest();
        System.out.println(new Gson().toJson(paginationNew));
        String baseQuery = "SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS";
        String paginatedQuery = AppUtil.buildPaginatedQueryForOracle(baseQuery, pagination);
        String paginatedQueryNew = AppUtil.buildPaginatedQueryForOracle(baseQuery, paginationNew);

        System.out.println(paginatedQuery);
        System.out.println(paginatedQueryNew);

        Query query = entityManager.createNativeQuery(paginatedQuery, UserModel.class);
        System.out.println("Query:");
        System.out.println(query);

        @SuppressWarnings("unchecked")
        List<UserModel> userList = query.getResultList();
        System.out.println(new Gson().toJson(userList));

        @SuppressWarnings("unchecked")
        List<NewUser> userListNew = newUserRepo.findAll(paginationNew);     
        System.out.println(new Gson().toJson(userListNew));

        DataTableResults<UserModel> dataTableResult = new DataTableResults<UserModel>();
        DataTableResults<NewUser> dataTableResultNew = new DataTableResults<NewUser>();
        dataTableResult.setDraw(dataTableInRQ.getDraw());
        dataTableResultNew.setDraw(dataTableInRQNew.getDraw());
        dataTableResult.setListOfDataObjects(userList);
        dataTableResultNew.setListOfDataObjects(userListNew);
        if (!AppUtil.isObjectEmpty(userList)) {
            dataTableResult.setRecordsTotal(userList.get(0).getTotalRecords()
                    .toString());
            if (dataTableInRQ.getPaginationRequest().isFilterByEmpty()) {
                dataTableResult.setRecordsFiltered(userList.get(0).getTotalRecords()
                        .toString());
            } else {
                dataTableResult.setRecordsFiltered(Integer.toString(userList.size()));
            }
        }
        if (!AppUtil.isObjectEmpty(userListNew)) {
            dataTableResultNew.setRecordsTotal(userListNew.get(0).getTotalRecords()
                    .toString());
            if (dataTableInRQ.getPaginationRequest().isFilterByEmpty()) {
                dataTableResultNew.setRecordsFiltered(userListNew.get(0).getTotalRecords()
                        .toString());
            } else {
                dataTableResultNew.setRecordsFiltered(Integer.toString(userListNew.size()));
            }
        }
        System.out.println(new Gson().toJson(dataTableResult));
        System.out.println(new Gson().toJson(dataTableResultNew));
        return new Gson().toJson(dataTableResult);
    }

So, I log out everything possible in the console. Here is the output:

{"uniqueId":"1579786571491","draw":"1","start":0,"length":5,"search":"","regex":false,"columns":[{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},{"index":1,"data":"name","name":"Name","searchable":true,"orderable":true,"search":"","regex":false},{"index":2,"data":"salary","name":"Salary","searchable":true,"orderable":true,"search":"","regex":false}],"order":{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},"isGlobalSearch":false,"maxParamsToCheck":3}
{"uniqueId":"1579786571491","draw":"1","start":0,"length":5,"search":"","regex":false,"columns":[{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},{"index":1,"data":"name","name":"Name","searchable":true,"orderable":true,"search":"","regex":false},{"index":2,"data":"salary","name":"Salary","searchable":true,"orderable":true,"search":"","regex":false}],"order":{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},"isGlobalSearch":false,"maxParamsToCheck":3}
{"pageNumber":0,"pageSize":5,"sortBy":{"mapOfSorts":{"id":"ASC"}},"filterBy":{"mapOfFilters":{},"globalSearch":false}}
{"pageNumber":0,"pageSize":5,"sortBy":{"mapOfSorts":{"id":"ASC"}},"filterBy":{"mapOfFilters":{},"globalSearch":false}}
SELECT * FROM (SELECT FILTERED_ORDERED_RESULTS.*, COUNT(1) OVER() total_records, ROWNUM AS RN FROM (SELECT BASEINFO.* FROM ( SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS ) BASEINFO ) FILTERED_ORDERED_RESULTS   ORDER BY id ASC ) WHERE RN > (0 * 5) AND RN <= (0 + 1) * 5 
SELECT * FROM (SELECT FILTERED_ORDERED_RESULTS.*, COUNT(1) OVER() total_records, ROWNUM AS RN FROM (SELECT BASEINFO.* FROM ( SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS ) BASEINFO ) FILTERED_ORDERED_RESULTS   ORDER BY id ASC ) WHERE RN > (0 * 5) AND RN <= (0 + 1) * 5 
Query:
org.hibernate.query.internal.NativeQueryImpl@3ea49a4
[{"id":3,"name":"user3","salary":"300","totalRecords":18},{"id":4,"name":"user4","salary":"400","totalRecords":18},{"id":5,"name":"user5","salary":"500","totalRecords":18},{"id":6,"name":"user6","salary":"600","totalRecords":18},{"id":7,"name":"user7","salary":"700","totalRecords":18}]
[{"id":3,"name":"user3","salary":"300","totalRecords":1},{"id":4,"name":"user4","salary":"400","totalRecords":2},{"id":5,"name":"user5","salary":"500","totalRecords":3},{"id":6,"name":"user6","salary":"600","totalRecords":4},{"id":7,"name":"user7","salary":"700","totalRecords":5}]
{"draw":"1","recordsFiltered":"18","recordsTotal":"18","data":[{"id":3,"name":"user3","salary":"300","totalRecords":18},{"id":4,"name":"user4","salary":"400","totalRecords":18},{"id":5,"name":"user5","salary":"500","totalRecords":18},{"id":6,"name":"user6","salary":"600","totalRecords":18},{"id":7,"name":"user7","salary":"700","totalRecords":18}]}
{"draw":"1","recordsFiltered":"1","recordsTotal":"1","data":[{"id":3,"name":"user3","salary":"300","totalRecords":1},{"id":4,"name":"user4","salary":"400","totalRecords":2},{"id":5,"name":"user5","salary":"500","totalRecords":3},{"id":6,"name":"user6","salary":"600","totalRecords":4},{"id":7,"name":"user7","salary":"700","totalRecords":5}]}

It helped me realize that:

  1. DataTableRequest incoming from the back is the same for both jpa and jdbc
  2. PaginationCriteria are also the same
  3. paginatedQuery having been made with the method specified above are the same.
  4. Differences are already seen in the Lists: where the Jpa list retrieved with native Query has totalRecords as 18 for every row, the JDBC repo with the same query returns 1,2,3... for every subsequent row.

It made me think that I should look at the Query made for JPA. But, as you see in the log, System.out.println wasn't able to decipher it for some reason. Any advice on how to decipher it and more importantly how to get the right total result for each row would be greatly appreciated!!!

来源:https://stackoverflow.com/questions/59880138/how-to-implement-server-side-processing-of-datatables-with-jdbc-so-that-it-pagin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!