I'm using OrientDB 2.0.5 release now and encountered one problem with my hook.
I have recursively linked object structure, which my hook need to process, and i've wrote simple demo showing problem below:
abstract class AbstractClass {
@OVersion
private Object version;
private AbstractClass parent;
@SuppressWarnings("unused")
public AbstractClass getParent() {
return parent;
}
public void setParent(AbstractClass parent) {
this.parent = parent;
}
}
@Entity
class MyClass extends AbstractClass {
private String name;
public MyClass() {
super();
name = "no-name";
}
@SuppressWarnings("unused")
public String getName() {
return name;
}
public void setName(String name) {
}
}
@Entity
class ContainerClass extends AbstractClass {
private AbstractClass item;
public AbstractClass getItem() {
return item;
}
public void setItem(AbstractClass item) {
this.item = item;
}
}
public void linkRecursiveObjectsHookUpdateTest() {
OObjectDatabaseTx db = new OObjectDatabaseTx("plocal:./LocalTestDB");
ODocumentHookAbstract hook = new ODocumentHookAbstract() {
@Override
public RESULT onRecordBeforeCreate(ODocument iDocument) {
System.out.println("This CREATE string appears one time (correct).");
return RESULT.RECORD_NOT_CHANGED;
}
@Override
public RESULT onRecordBeforeUpdate(ODocument iDocument) {
System.out.println("This UPDATE string appears two times! (incorrect?) " + Arrays.asList(iDocument.getDirtyFields()));
// Here i have some 'pacth' code, which fix this problem for me, but i'm not sure, if it is correct way to fix
// OObjectDatabaseTx db;
// if (iDocument.getDatabase().getDatabaseOwner() instanceof OObjectDatabaseTx) {
// db = (OObjectDatabaseTx) iDocument.getDatabase().getDatabaseOwner();
// } else {
// db = new OObjectDatabaseTx((ODatabaseDocumentTx) iDocument.getDatabase().getDatabaseOwner());
// }
// db.unsetDirty(db.getUserObjectByRecord(iDocument, null));
return RESULT.RECORD_NOT_CHANGED;
}
@Override
public DISTRIBUTED_EXECUTION_MODE getDistributedExecutionMode() {
return DISTRIBUTED_EXECUTION_MODE.BOTH;
}
};
hook.setIncludeClasses("MyClass");
db.registerHook(hook, HOOK_POSITION.FIRST); // can be any position
if (!db.exists()) {
db.create();
} else {
db.open("admin", "admin");
}
db.setAutomaticSchemaGeneration(true);
db.getEntityManager().registerEntityClass(MyClass.class);
db.getEntityManager().registerEntityClass(ContainerClass.class);
db.reload(); // Sometimes entity registration transparently fails and first save command fires exception (first try block), seems that reload helps (another bug?)
MyClass obj = new MyClass();
obj.setName("name");
ContainerClass box = new ContainerClass();
obj.setParent(box);
box.setItem(obj);
db.begin();
try {
box = db.save(box);
db.commit();
} catch (Exception e) {
db.rollback();
db.close();
throw e;
}
obj = (MyClass) box.getItem();
db.begin();
try {
obj.setName("new-name");
obj = db.save(obj); // I have first even triggering here
db.commit(); // and the second here
} catch (Exception e) {
db.rollback();
throw e;
} finally {
db.close();
}
}
I must notice, that problem occurs only when i register my hook from client-side and it not exists on server-side registered hook.
For me is important to understand, is this problem is bug or not? And if not, then why and how it can be evaded for me?