3

I'm having issues when trying to get audited entities referencing to entities that are not audited. In our application, certain entities are bootstrapped without the use of hibernate, those entities are our meta-model and do not need to be audited.

Working example:

public class A {
  private String id;
  private List<B> attributeReferences;
}

public class B {
  private String id;
  private A attributeReference;
}

If I execute the code:

A rev1 = getAuditReader().find(A.class, "foo", 1);
A rev2 = getAuditReader().find(A.class, "foo", 2);
A rev3 = getAuditReader().find(A.class, "foo", 3);

Everything goes well, however if I try to get a version of B the error occurs:

B rev2 = getAuditReader().find(B.class, "bar", 2);

org.hibernate.ObjectNotFoundException: No row with the given identifier exists [metafoo]

Envers successfully does the lookup of the B entity with a lazy reference to my metafoo entity. However when trying to store that in its cache the hashcode method of my B entity gets called, which in turn does a lookup for metafoo which does not exist in the audit tables, raising the exception.

Is there a way I could ignore those inexistent references instead of throwing this error? (maybe by excluding such references in the query)

How to deal with inexistent data altogether (suppose we deleted all entries older than 1 month from the audit table) how could we still query entities referencing to inexistent ones?

PS:

I'd like not to modify the hashcode function if possible
I'd like not to audit my meta model

Table structure:

table A:

ID  
----------------------------------------
metaFooAttribute  
fooAttribute
foo

table A_AUD:

REV    REVTYPE    ID  
----------------------------------------
1      0          fooAttribute
1      0          foo  
2      1          foo  
3      1          foo  

table B:

ID
----------------------------------------
bar

table B_AUD:

REV    REVTYPE    ID    ATTRIBUTE_ID  
----------------------------------------
1      0          bar   metaFooAttribute
1      0          bar   fooAttribute
2      1          bar   fooAttribute

Stacktrace:

org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [playground.test.A#metafoo]
at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:435)
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:189)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:178)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:189)
at playground.test.A$$EnhancerByCGLIB$$3cdb0441.hashCode(<generated>)
at playground.test.B.hashCode(B.java:120)
at org.hibernate.envers.tools.Triple.hashCode(Triple.java:73)
at java.util.HashMap.put(HashMap.java:372)
at org.hibernate.envers.reader.FirstLevelCache.putOnEntityNameCache(FirstLevelCache.java:94)
at org.hibernate.envers.entities.EntityInstantiator.createInstanceFromVersionsEntity(EntityInstantiator.java:105)
at org.hibernate.envers.entities.EntityInstantiator.addInstancesFromVersionsEntities(EntityInstantiator.java:113)
at org.hibernate.envers.query.impl.EntitiesAtRevisionQuery.list(EntitiesAtRevisionQuery.java:110)
at org.hibernate.envers.query.impl.AbstractAuditQuery.getSingleResult(AbstractAuditQuery.java:108)
at org.hibernate.envers.reader.AuditReaderImpl.find(AuditReaderImpl.java:119)
at org.hibernate.envers.reader.AuditReaderImpl.find(AuditReaderImpl.java:94)
at playground.test.TestEnvers.testGetAttribute(TestActivityStream.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Edit:

I found this post interesting but it does not solve the problem as my reference is of type A so the annotation @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) does not work.

Community
  • 1
  • 1
phury
  • 2,123
  • 2
  • 21
  • 33

1 Answers1

1

Maybe try adding @NotAudited to the meta-field. Then the field won't be audited, but it looks as if you don't want to audit it. Otherwise @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) is the way to go.

adamw
  • 8,038
  • 4
  • 28
  • 32
  • The issue is that the reference is is not always an ID to a meta attribute. If it is a meta attribute, it is not audited (we bootstrap it without envers) otherwise it is added by hibernate (so it gets audited) I updated my question to better explain the issue – phury Sep 07 '12 at 08:54
  • Hmm I don't think I understand. You have an attribute on an entity, which you don't want to be audited, yes? But it is filled normally with some other mechanism? – adamw Sep 09 '12 at 18:17
  • Thans for your advise Adam. Its a chicken-egg problem. I have entities that are referencering meta-entities that are themeselve entities. We finally solved the issue by auditing the meta-entities in the system as well. They will stay there forever but it is not really an issue. Great work for the rest by the way ;) – phury Oct 16 '12 at 09:06