【发布时间】:2019-05-24 04:03:36
【问题描述】:
我正在使用hibernate 5.2 编写java 应用程序,但没有HQL
有两个表,Transactions 和 ResponseCode
我想用 Hibernate 生成的 select 语句的逻辑应该是这样的 select bellow
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 )
但是我的代码有问题,这里是我的实现 sn-p
交易实体
@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
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
实现代码
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);
Hibernate 生成两个 select 语句,第一个语句获取事务列表,第二个语句获取包含在事务列表中的响应代码详细信息。
例子: 如果有30000个交易,15000个交易有000响应码,5000个交易有116个响应码,10000个交易有400个响应码,会运行第二个select语句 3 次,分别为 000,116 和 400 rcCode。
但问题是ResponseCode 表包含一种响应代码的多种语言
第一个select语句包含对语言的限制,但是第二个select语句没有这个限制,并且它不测量第一个语句中提供的语言,事务对象的最终结果包含一些事务en语言rc描述以及一些交易ge语言rc描述。
我认为这取决于oracle最后选择了哪种语言描述
Hibernate 生成的选择 I
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
Hibernate 生成的选择 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 = ?'
P.s 如果我建立
OneToMany关系,它将获得 30000 笔交易和 执行 30000 次附加查询以获取每个响应的代码描述 运算,称为N+1问题
你知道怎么解决吗?
【问题讨论】:
-
这里没有错误。 where 子句不会更改实体包含的内容。它会更改查询检索到的实体。因此,如果您的 where 子句允许选择事务 t,当您请求 t 的响应代码时,您将始终得到 t 的响应代码。而且,如果有多行相同的响应码,那么响应码显然不能是实体的ID:ID应该是唯一标识一个实体,就像一个主键一样。
-
@JB Nizet 我已经编辑了问题,请检查您是否有任何想法如何解决它
标签: java sql oracle hibernate jpa