简体   繁体   中英

Using @IdClass with Hibernate and arquillian force CascadeType.Insert on a ManyToOne foreign key object that is part of entity composite primary key

I am trying to persist a new Order object from my arquillian test class. The order entity contains a list of OrderDetail entity which has a composed primary key of 4 fields.

But while Hibernate is trying to insert the new OrderDetail object it also insert the NOT NEW Item object (Item is one of the main PK fields in the OrderDetail entity and annotated with @ID ) , and this results in a unique constrain exception from the Item table in the DB.

Note that I removed the CascadeType from the Item @OneToMany annotation and tried also the CascadeType.Refresh but I got the same result and nothing changed. It works as it force CascadeType.Insert in all cases.

It worked as expected when I used @EmbeddedId annotation instead of @IDClass But I want to know why it did not work with @IDClass ? is it a bug in Hibernate ? It should work perfectly as per the JPA 2.1 specification .

Order Entity

@Entity
@Table(name = "ORDERS")
public class Orders extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ORDERNO")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long orderNo ;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "order", fetch = FetchType.LAZY)
    private List<OrderDetail> orderDetailsList ;

    // setters and getters
}

OrderDetail Entity

@Entity
@Table(name = "ORDERDETAILS")
@IdClass(OrderDetailsPK.class)
public class OrderDetail extends BaseEntity {

private static final long serialVersionUID = 1L;

@Id
@JoinColumn(name = "ORDERNO", referencedColumnName = "ORDERNO")
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private Orders order;

@Id
@JoinColumn( name = "ITEMNO", referencedColumnName = "ITEMNO", insertable = false, updatable = false)
@ManyToOne(cascade = CascadeType.REFRESH,optional = false, fetch = FetchType.LAZY)
//@Cascade({CascadeType.DETACH}) // I tried this but did not work, it keep try to insert the item.
private Item item;

@Id
@Column(name = "LINETYPE")
private String lineType;

@Id
@Column(name = "PROMITEMNO")
private String promItemNo;

Item Entity

@Entity
@Table(name = "ITEM")
public class Item extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ITEMNO")
    private String itemno;
    // setters and getters

   @Override
   public int hashCode() {
    int hash = 0;
    hash += (itemno != null ? itemno.hashCode() : 0);
    return hash;
   }

   @Override
   public boolean equals(Object object) {
    if (!(object instanceof Item)) {
        return false;
    }
    Item other = (Item) object;
    System.out.println("Item Equal Method = " + !((this.itemno == null &&        other.itemno != null) || (this.itemno != null && !this.itemno.equals(other.itemno))));
    return !((this.itemno == null && other.itemno != null) || (this.itemno != null && !this.itemno.equals(other.itemno)));
}

  @Override
  public String toString() {
    return "com.unilever.sas.model.entities.masterdata.Item[ itemno=" + itemno + " ]";
}

}

OrderDetailsPK

public class OrderDetailsPK  implements Serializable 
{

    private static final long serialVersionUID = 1L;

    private Long order;
    private String item;
    private String lineType;
    private String promItemNo;

    public OrderDetailsPK() {
    }

    public OrderDetailsPK(Long order, String item, String lineType, String promItemNo) {
        this.order = order;
        this.item = item;
        this.lineType = lineType;
        this.promItemNo = promItemNo;
    }

    public Long getOrder() {
        return order;
    }

    public String getItem() {
        return item;
    }

    public String getLineType() {
        return lineType;
    }


    public String getPromItemNo() {
        return promItemNo;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 73 * hash + Objects.hashCode(this.order);
        hash = 73 * hash + Objects.hashCode(this.item);
        hash = 73 * hash + Objects.hashCode(this.lineType);
        hash = 73 * hash + Objects.hashCode(this.promItemNo);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final OrderDetailsPK other = (OrderDetailsPK) obj;
        if (!Objects.equals(this.item, other.item)) {
            return false;
        }
        if (!Objects.equals(this.lineType, other.lineType)) {
            return false;
        }
        if (!Objects.equals(this.promItemNo, other.promItemNo)) {
            return false;
        }
        if (!Objects.equals(this.order, other.order)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "OrderDetailsPK{" + "order=" + order + ", item=" + item + ", lineType=" + lineType + ", promItemNo=" + promItemNo + '}';
    }

Arquillian Test

@RunWith(Arquillian.class)
public class OrdersFacadeTest
{


@Inject
OrdersFacadeLocal ordersFacade ;

@Inject    
ItemFacadeLocal itemFacade ;

@Test
public void testCreateOrder() throws Exception 
{
    Item item = itemFacade.find("20247912");
    Orders order = new Orders();

    OrderDetail orderDetail = new OrderDetail();
    orderDetail.setOrder(order);
    orderDetail.setItem(item);
    orderDetail.setLineType("NLI");
    orderDetail.setPromItemNo("99999");

    List<OrderDetail> orderDeialsList = new ArrayList<>();
    orderDeialsList.add(orderDetail);

    order.setOrderDetailsList(orderDeialsList);      

    ordersFacade.create(order);

    Orders createdOrder = ordersFacade.find(order.getOrderNo());
    assertEquals(order, createdOrder);
}

It could be a bug, but there are also some strange mapping choices here as well.

Why does the @JoinColumn is not allowed to set the FK on insert or update? Who should set the FK in this case?

@JoinColumn( 
    name = "ITEMNO", 
    referencedColumnName = "ITEMNO", 
    insertable = false, updatable = false
)

If you can replicate it with a test case , then you should open a Jira issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM