1

Parent is product entity, and child is stock entity distinguished by time(like a hotel stock model that the stock of every booking day should be different and manipulated separately)

The ProductEntity is defined as:

@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){...}
     ....
}

And the StockEntity is defined as:

@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;
    }

    ....
}

Since you are aware, I use productId of ProductEntity as a foreign key and the startTime(a long type time-stamp) as a primary key.

Then I want to update a specific stock item of the product by:

 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();
     }
 }

With above DAO code, I expect to modify the stock amount of specific stock item(identified by startTime) of specific product.

But some times I will got a update count mis-match with expected error when there are stock items with same startTime and different product id, I triggered the hibernate log and find that, in the sql generated by hibernate, the update SQL only contains the startTime(which is explicit as a @Id) but no productId in the query condition:

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

So, How to solve this?

armnotstrong
  • 8,605
  • 16
  • 65
  • 130

1 Answers1

1

Just because productEntity is a join column does not make it part of the ID. Either you'll have to use a composite ID containing both the time stamp and the product ID (see for instance How to map a composite key with Hibernate?), but perhaps easier is to not define the timestamp as ID in the first place, but have a normal "autoincrement" or similar ID, and have timestamp a normal column.

Community
  • 1
  • 1
geert3
  • 7,086
  • 1
  • 33
  • 49
  • Seems the only way to do that is make another auto_increment primary key as the identity of stock Entity, otherwise things will be really complex. Thanks – armnotstrong Jul 30 '15 at 12:40