Hibernate update child from parent, joined column is not specified in generated sql 查询条件
Hibernate update child from parent, joined column is not specified in generated sql query condition
parent为产品实体,child为按时间区分的库存实体(如酒店库存模型,每个预订日的库存应该不同,单独操作)
ProductEntity
定义为:
@Entity
@Table(name = "product")
public class ProductEntity{
....
private long productId;
private List<StockEntity> stockEntityList;
....
@Id
@Column(name="productId")
public long getProductId(){
return this.productId;
}
@OneToMany(mappedBy="productEntity", fetch= FetchType.EAGER
cascade={CascadeType.ALL,CascadeType.PERSIST,CascadeType.MERGE},
orphanRemoval = true)
public List<StockEntity> getStockEntityList(){
return this.stockEnityList;
}
public void setStockEntityList(List<StockEntity> stockEntityList){...}
....
}
而 StockEntity
定义为:
@Entity
@Table(name = "stock")
public class StockEntity{
...
private ProductEntity productEntity;
private long startTime;
...
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="productId")
public ProductEntity getProductEntity(){
return this.producntEntity;
}
@Id
@Column(name="startTime")
public long getStartTime(){
return this.startTime;
}
....
}
既然你知道,我使用 ProductEntity
的 productId 作为外键,startTime
(长类型时间戳)作为主键。
然后我想通过以下方式更新产品的特定库存项目:
public void consumeStockQuantity(long productId, long startTime, int count){
Session session = HBSession.getSession();
Transaction tx = session.beginTransaction();
ProductEntity productEntity = session.get(productId, ProductEntity.class);
for(StockEntity stockEntity: productEntity.getStockEntityList()){
if(stockEntity.getStartTime() == startTime){
stockEntity.setQuantity(stockEntity.getQuantity-count);
}
}
try{
session.update(productEntity);
tx.commit();
}catch(Exception e){
e.printStackTrace();
tx.rollback();
}finally{
session.close();
}
}
使用上面的 DAO 代码,我希望修改特定产品的特定库存项目(由 startTime
标识)的库存量。
但有时当存在具有相同 startTime
和不同产品 ID 的库存商品时,我会得到一个 update count mis-match with expected error
,我触发休眠日志并发现,在 sql由休眠生成,更新 SQL 仅包含 startTime
(显式为 @Id
)但查询条件中没有 productId
:
Hibernate:
update
test.stock
set
marketPrice=?,
productId=?,
purchasePrice=?,
quantity=?,
sellPrice=?
where
startTime=? //here missing productId which is a joinedColumn
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [FLOAT] - [1.2]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - [1075]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [FLOAT] - [0.01]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - [1000]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [5] as [FLOAT] - [0.01]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [6] as [BIGINT] - [1438175312412]
Exception in thread "main" org.hibernate.jdbc.BatchedTooManyRowsAffectedException: Batch update returned unexpected row count from update [0]; actual row count: 2; expected: 1
那么,如何解决这个问题?
仅仅因为 productEntity
是一个连接列并不能使它成为 ID 的一部分。
您要么必须使用包含时间戳和产品 ID 的复合 ID(例如,请参阅
How to map a composite key with Hibernate?),但也许更容易的是首先不将时间戳定义为 ID,而是使用普通的 "autoincrement" 或类似的 ID,并将时间戳定义为普通的列。
parent为产品实体,child为按时间区分的库存实体(如酒店库存模型,每个预订日的库存应该不同,单独操作)
ProductEntity
定义为:
@Entity
@Table(name = "product")
public class ProductEntity{
....
private long productId;
private List<StockEntity> stockEntityList;
....
@Id
@Column(name="productId")
public long getProductId(){
return this.productId;
}
@OneToMany(mappedBy="productEntity", fetch= FetchType.EAGER
cascade={CascadeType.ALL,CascadeType.PERSIST,CascadeType.MERGE},
orphanRemoval = true)
public List<StockEntity> getStockEntityList(){
return this.stockEnityList;
}
public void setStockEntityList(List<StockEntity> stockEntityList){...}
....
}
而 StockEntity
定义为:
@Entity
@Table(name = "stock")
public class StockEntity{
...
private ProductEntity productEntity;
private long startTime;
...
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="productId")
public ProductEntity getProductEntity(){
return this.producntEntity;
}
@Id
@Column(name="startTime")
public long getStartTime(){
return this.startTime;
}
....
}
既然你知道,我使用 ProductEntity
的 productId 作为外键,startTime
(长类型时间戳)作为主键。
然后我想通过以下方式更新产品的特定库存项目:
public void consumeStockQuantity(long productId, long startTime, int count){
Session session = HBSession.getSession();
Transaction tx = session.beginTransaction();
ProductEntity productEntity = session.get(productId, ProductEntity.class);
for(StockEntity stockEntity: productEntity.getStockEntityList()){
if(stockEntity.getStartTime() == startTime){
stockEntity.setQuantity(stockEntity.getQuantity-count);
}
}
try{
session.update(productEntity);
tx.commit();
}catch(Exception e){
e.printStackTrace();
tx.rollback();
}finally{
session.close();
}
}
使用上面的 DAO 代码,我希望修改特定产品的特定库存项目(由 startTime
标识)的库存量。
但有时当存在具有相同 startTime
和不同产品 ID 的库存商品时,我会得到一个 update count mis-match with expected error
,我触发休眠日志并发现,在 sql由休眠生成,更新 SQL 仅包含 startTime
(显式为 @Id
)但查询条件中没有 productId
:
Hibernate:
update
test.stock
set
marketPrice=?,
productId=?,
purchasePrice=?,
quantity=?,
sellPrice=?
where
startTime=? //here missing productId which is a joinedColumn
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [FLOAT] - [1.2]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - [1075]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [FLOAT] - [0.01]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - [1000]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [5] as [FLOAT] - [0.01]
HibernateLog --> 15:35:27 TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [6] as [BIGINT] - [1438175312412]
Exception in thread "main" org.hibernate.jdbc.BatchedTooManyRowsAffectedException: Batch update returned unexpected row count from update [0]; actual row count: 2; expected: 1
那么,如何解决这个问题?
仅仅因为 productEntity
是一个连接列并不能使它成为 ID 的一部分。
您要么必须使用包含时间戳和产品 ID 的复合 ID(例如,请参阅
How to map a composite key with Hibernate?),但也许更容易的是首先不将时间戳定义为 ID,而是使用普通的 "autoincrement" 或类似的 ID,并将时间戳定义为普通的列。