TopLink EntityManager неправильно сохраняет объект

Очень ценю ЛЮБУЮ помощь (по крайней мере, способы отследить основную причину проблемы), потому что я боролся с этим несколько дней и не нашел даже обходного пути.

Сама проблема: у меня есть несколько сущностей, все они работают хорошо - persist(), find() и т. д., кроме одного метода, в котором я создаю две разные сущности (Заказ и Предметы, в одном заказе может быть много Предметов). После вызова em.persist(..) заказ сохраняется, и я вижу его идентификатор, сгенерированный БД, элемент сохраняется в БД (я вижу это через SELECT непосредственно в БД), но он показывает ID = 0. И что бы я ни делал, это всегда 0 (например, когда я открываю заказ, я все еще вижу его ID = 0), пока я не перезапущу сервер - тогда он показывает правильный ID предмета. Код метода (после регистрации я добавил фактические значения, которые я получаю):

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
}

Класс заказа:

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

}

Класс элемента (удалены геттеры и сеттеры, чтобы сделать его более читабельным): @Entity @Table(name="items") public class Item реализует 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;

}

У меня были некоторые мысли о кэшировании, поэтому я добавил в свой файл persistence.xml строки

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

но и это не помогло


person user2676881    schedule 22.08.2013    source источник


Ответы (3)


Попробуйте изменить int на Integer

private Integer orderId;

а также геттеры и сеттеры.

person Alex    schedule 23.08.2013
comment
Спасибо, но это не помогает. Во всяком случае, Order (и другие объекты) имеет идентификатор int, и он работает. К настоящему времени я добавил метод, который находит максимальный идентификатор из элементов и устанавливает увеличенное значение в качестве идентификатора элемента перед сохранением, он работает, но настолько уродлив, что у меня глаза кровоточат, когда я его вижу :) - person user2676881; 23.08.2013

Вы упомянули, что элементу присвоено значение идентификатора в базе данных, но вы пропустили аннотацию @GeneratedValue(strategy=GenerationType.IDENTITY), которая у вас есть в заказе. Это то, что говорит JPA, что db контролирует значение, в противном случае он ожидает, что приложение установит его, сохраняя по умолчанию 0.

person Chris    schedule 23.08.2013

после вызова em.persist(obj) вызовите em.flush();. Он должен работать.

лучше иметь частный метод сохранения, например

private void save(object obj)
{
    em.persist(obj);
    em.flush();
}
person Sudheendra    schedule 23.08.2013