Update is ignored by ObjectDB

#1

Hi! Sorry for my bad english skills. When I execute fulfilOrder, only Order entity is updated in the database, and User entity remains modified only in code, even if I go:

user = smdb.find(User.class, user.id);

In this source highlighted lines modifying entity, but not the database.

@Stateless public class SMDB {
@PersistenceContext(unitName = "SM") private EntityManager smdb;
@PersistenceContext(unitName = "SMShop") private EntityManager shopdb;

...

public Order fulfilOrder(Long orderID, Long userID, int itemID) {
  Order order = shopdb.find(Order.class, orderID);
  if (order == null) {
   User user = smdb.find(User.class, userID);
   ShopItem item = shopdb.find(ShopItem.class, itemID);
   if (item == null || user == null) return null;
   user.money += item.total; // <-this
   smdb.merge(user); // <-and this
   order = new Order(orderID, user, item);
   shopdb.persist(order);
  }
  return order;
}

If I delete them and add them outside, everything work fine.

@EJB SMDB lib;

...

     Order orderInfo = lib.fulfilOrder(orderID, userID,itemID);
      User user = lib.getUser(userID);//it's em.find(user_id)
      user.money += item.total; // <- moved this lines here
      lib.updateUser(user);// it's em.merge(user);

So my question : Is it impossible to perform two transactions in one method or it's a bug?

Thanks.

#2

Try to replace direct field update:

    user.money += item.total

with update using a new method in User:

    user.addMoney(item.total);

Of course, you have to implement the addMoney method.

Persistent fields should not be defined as public and accessed or modified directly from other classes.

 

ObjectDB Support
#3

Thanks! This works!

user.addMoney(item.total);

Persistent fields should not be defined as public and accessed or modified directly from other classes.

"should not" is more like "better not", and not "disallowed".

My choice is reasonable: Java communicates with Flash (AS3) client, they both implement same game logic, but Flash has a way different getter/setter syntax. Using direct access to fields simplifies code porting and direct JSON parsing. User has 100+ fields and involved in almost all classes.

On the other hand different behavior in user.money=x and  user.addMoney(x) when it's still only {money=x} seems OOP illogical. Especially when it worked for me everywhere except commit transactions in different entity managers.

I think that this problem is related to EJB injection behavior of ObjectDB, however, is only my supposition. For me is important not only how to quick-fix the bug but, mostly, understand why it occured.

I wrote this reply only for you [ObjectDB Developers Team] to consider opportunity of using direct access to persistant fields and to figure out why it's not working now in some cases. 

Anyway, I want to thank you for your ObjectDB. It's realy a great project!

Best Regards, Vladimir!

#4

Automatic update following direct modification of fields is supported by ObjectDB if any of the following conditions applies:

  • The entity classes are not enhanced.
  • ObjectDB is forced to use reflection rather than the enhancement.
  • Enhancement is used but not only entity classes are enhanced but also any code that accesses a persistent field directly.

In other words, if you use enhancement, you must enhance the entity classes as well as the code that accesses persistent fields directly. This is not done automatically, for example, when using Java Agent Enhancement.

This is also explained in the manual in more details:

There is one case, however, where enhancement is required. Non persistable classes that access directly (not through methods) persistent fields of enhanced classes must also be enhanced. It is a good practice (and actually required by JPA but not enforced by ObjectDB) to avoid accessing persistent fields of other classes directly.  Rather, the accessor and mutator methods of the desired class should be used (e.g. by using the get and set methods). If you follow this practice only user defined persistable classes should need to be enhanced.

So regarding this statement in the manual:

Persistent fields should not be defined as public and accessed or modified directly from other classes.

The wording "should not" may be more appropriate than "must not", because you may define these fields as public if you access them only from enhanced classes, or do not use enhancement.

ObjectDB Support

Reply