jib*_*One 12 java sql oracle hibernate jpa
我正在编写java应用程序,hibernate 5.2但没有HQL
有两张桌子,Transactions和ResponseCode
我希望由Hibernate生成的select语句的逻辑看起来应该如下所示
SELECT t.tranType
      ,t.tranId
      ,t.requestDate
      ,t.rcCode
      ,t.tranAmount
      ,r.description
      ,r.status
  FROM transactions t
  LEFT OUTER JOIN responseCode r
    ON t.rcCode = r.rcCode
   AND (r.lang = 'en')
 WHERE (t.merchant_id =5 )
Run Code Online (Sandbox Code Playgroud)
但是我的代码出了问题,这是我的实现代码段
交易实体
@Entity
@Table(name = "transactions")
public class Transaction implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
        @Column(name = "merchant_id", nullable = true)
        private String merchantID;
        @Column(name = "tran_amount", nullable = true)
        private String tranAmount;
        @Id
        @Column(name = "tran_type", nullable = true)
        private String tranType;
        @Column(name = "auth_request_date", nullable = true)
        @Temporal(TemporalType.TIMESTAMP)
        private Date authRequestDate;
        @Id
        @Column(name = "tran_id", nullable = true)
        private String tranID;
        @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
        @JoinColumn(name="rc")
        private ResponseCode rc;
        // Contructos and getters/setters
Run Code Online (Sandbox Code Playgroud)
ResponseCode实体
@Entity
@Table(name = "response_codes")
public class ResponseCode implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Column(name = "response_code")
    private String rcCode;
    @Column(name = "rc_status")
    private String rcStatus;
    @Column(name = "rc_description")
    private String rcDesc;
    @Column(name = "rc_lang")
    private String rcLang;
    // Contructos and getters/setters
Run Code Online (Sandbox Code Playgroud)
实施代码
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Transaction> criteria = builder.createQuery(Transaction.class);
Root<Transaction> transaction = criteria.from(Transaction.class);
Join<Transaction, ResponseCode> bJoin = transaction.join("rc",JoinType.LEFT);
bJoin.on(builder.equal(bJoin.get("rcLang"), tRequest.getLang()));
Predicate predicate = builder.and(transaction.get("merchantID").in(tRequest.getMerchantList()));
predicate = builder.and(predicate, builder.between(transaction.get("authRequestDate"), dateFrom, dateTo));
criteria.where(predicate);
Run Code Online (Sandbox Code Playgroud)
Hibernate生成两个select语句,第一个语句获取事务列表,第二个语句获取包含在事务列表中的响应代码详细信息.
例如: 如果有30000个事务,15000个事务有000个响应代码,5000个事务有116个响应代码,10000个事务有400个响应代码,它将运行第二个select语句三次,分别为000,116和400个rcCode.
但问题是该ResponseCode表包含一个响应代码的几种语言

第一个select语句包含对语言的限制,但第二个select语句没有这个限制,并且它不计量在第一个语句中提供哪种语言,事务对象的最终结果包含一些事务en语言rc描述和某些事务ge语言rc说明.
我认为这取决于oracle最后选择的语言描述
Hibernate生成选择我
SELECT t.tran_type
      ,t.tran_id
      ,t.auth_request_date
      ,t.merchant_id
      ,t.rc
      ,t.tran_amount
  FROM transactions t
  LEFT OUTER JOIN response_codes r
    ON t.rc = r.response_code
   AND (r.rc_lang = ?)
 WHERE (t.merchant_id IN (?))
   AND (t.AUTH_REQUEST_DATE BETWEEN ? AND ?)
 ORDER BY t.AUTH_REQUEST_DATE ASC
Run Code Online (Sandbox Code Playgroud)
Hibernate生成了select II
SELECT r.response_code  
      ,r.rc_description 
      ,r.rc_lang        
      ,r.rc_status      
  FROM response_codes r
 WHERE r.response_code = ? 
 //this select statement should have 'AND r.rc_lang = ?'
Run Code Online (Sandbox Code Playgroud)
Ps 如果我
OneToMany建立关系,它将获得30000个事务并执行30000个额外查询以获取每个操作的响应代码描述
你知道怎么解决吗?
最后我发现
Criteria API 不支持加入不相关的实体。JPQL 也不支持这一点。然而,Hibernate 从 5.1 开始在 HQL 中支持它。 https://discourse.hibernate.org/t/join-two-table-when-both-has-composite-primary-key/1966
也许有一些解决方法,但在这种情况下,我认为更好的方法是使用 HQL 而不是 Criteria API。
这是HQL实现代码片段(实体类中没有任何改变)
String hql = "FROM Transaction t \r\n" + 
             " LEFT OUTER JOIN FETCH t.rc r \r\n" +
             " WHERE (t.merchantID IN (:merchant_id))\r\n" +
             " AND (t.authRequestDate BETWEEN :from AND :to)\r\n" +
             " AND (r.rcLang = :rcLang or r.rcLang is null)\r\n";
Query query =  session.createQuery(hql,Transaction.class);
query.setParameter("merchant_id", tRequest.getMerchantList());
query.setParameter("rcLang", tRequest.getLang());
query.setParameter("from", dateFrom);
query.setParameter("to", dateTo);
List<Transaction> dbTransaction = query.getResultList();
Run Code Online (Sandbox Code Playgroud)
        |   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           1468 次  |  
        
|   最近记录:  |