TopLink EntityManager doesn't save object properly

416 views Asked by At

Really appreciate ANY help (at least ways how to trace root cause of the problem) because I've been fighting with this for several days and didn't find even workaround.

The problem itself: I have a few entities, all of them work good - persist(), find() etc. except one method where I create two different entities (Order and Items, one order can have many Items). After calling em.persist(..) order is saved and I see its id generated by DB, item is saved to DB (I see it through SELECT directly in DB) but it shows ID=0. And whatever I do it always 0 (e.g. when I open the order I still see its ID=0) until I restart server - then it shows correct ID of item. Code of the method (after logging I added actual values I get):

public void createOrderFromItems(ArrayList<TehnomirItemDTO> items, User user) {

    Order ord = new Order();
    User managers = getUserByEmail(Constants.ALL_MANAGERS_GROUP);
    ord.setAssignedTo(managers);
    Date date = new Date();
    ord.setCreatedOn(date);
    User customer = user;
    ord.setCustomer(customer);

    BigDecimal custBalance = new BigDecimal(0);
    ArrayList<Balance> balances = getBalanceForUser(customer);
    for (Balance b:balances) {
        custBalance.add(b.getAmount());
    }
    logger.debug("before1. order: "+ord.getOrderId()); //here I get 0
    em.persist(ord);
    logger.debug("before2. order: "+ord.getOrderId()); //still 0

    State new_state = getStateByName(SharedConstants.STATE_NEW);
    logger.debug("before3. order: "+ord.getOrderId()); //here I get actual ID, generated by DB, e.g. 189
    State overpriced = getStateByName(SharedConstants.STATE_LIMIT_EXCEEDED);
    ArrayList<Item> itemList = new ArrayList<Item>();
    for (TehnomirItemDTO tid:items) {
        Item item = new Item(tid);
        item.setOrder(ord);
        logger.debug("order inside2:"+ord.getOrderId()); //again, actual ID

        item.setPriceInt(tid.getPrice_int());
        custBalance = custBalance.subtract(item.getPriceInt());
        if (custBalance.floatValue()>0) {
            item.setStateBean(new_state);
        } else item.setStateBean(overpriced);       
        logger.debug("item before:"+item.getItemId()); //here I get 0
        em.persist(item);
        item = em.merge(item);
        em.setFlushMode(FlushModeType.COMMIT);//added just in case it would work but it didn't
        em.flush();//same as previous line

        Item tst = getItemByID(1);
        logger.debug("item after:"+item.getItemId()+"  ord:"+ord.getOrderId()); //again, orderID is correct, itemID is 0
        itemList.add(item);
    }
    ord.setItems(itemList);

    State new_state2 = getStateByName(SharedConstants.STATE_NEW);
    logger.debug(ord.getItems().get(0).getItemId()+" order: "+ord.getOrderId());//again, orderID is correct, itemID is 0
}

Order class:

@Entity
@Table(name="orders")
public class Order implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY/*,     generator="ORDERS_ORDERID_GENERATOR"*/)
    @Column(name="ORDER_ID")
    private int orderId;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="CREATED_ON")
    private Date createdOn;

    //bi-directional many-to-one association to Item
    @OneToMany(mappedBy="order")
    private List<Item> items;


    //uni-directional many-to-one association to User
    @ManyToOne
    @JoinColumn(name="ASSIGNED_TO")
    private User assignedTo;

    //uni-directional many-to-one association to User
    @ManyToOne
    @JoinColumn(name="CUSTOMER")
    private User customer;

    public Order() {
    }

    public int getOrderId() {
        return this.orderId;
    }

}

Item class (removed getters and setters to make it more readable): @Entity @Table(name="items") public class Item implements Serializable { private static final long serialVersionUID = 1L;

    @Id
    @Column(name="ITEM_ID")
    private int itemId;

    private String code;

    private BigDecimal weight;

    public BigDecimal getWeight() {
        return weight;
    }

    public void setWeight(BigDecimal weight) {
        this.weight = weight;
    }

    private String comments;//any additional info user'd like to add

    private String description;

    @Column(name="EXT_ID")
    private int extId;

    private String manufacturer;

    @Column(name="PRICE_EXT")
    private BigDecimal priceExt;

    @Column(name="PRICE_INT")
    private BigDecimal priceInt;

    private String region;

    private String term;

    //bi-directional many-to-one association to Order
    @ManyToOne(cascade=CascadeType.PERSIST)
    @JoinColumn(name="ORDER_ID")
    private Order order;

    //bi-directional many-to-one association to State
    @ManyToOne
    @JoinColumn(name="STATE")
    private State state;

}

I had some thoughts about caching so I added to my persistence.xml lines

property name="toplink.cache.type.default" value="NONE"
property name="toplink.cache.type.Order" value="NONE"

but it didn't help either

3

There are 3 answers

1
Alex On

Try to change int to Integer

private Integer orderId;

and getters and setters as well.

0
Chris On

You mention Item is assigned an ID value by the database, but missed the @GeneratedValue(strategy=GenerationType.IDENTITY) annotation you have on order. This is what tells JPA the db controls the value, otherwise it expects the application to set it, keeping it the default 0.

0
Sudheendra On

after calling em.persist(obj), call em.flush();. It should work.

better have a private method save like

private void save(object obj)
{
    em.persist(obj);
    em.flush();
}