1 2 Previous Next 16 Replies Latest reply on Sep 13, 2009 1:45 PM by eugene.goroschenya

    ManyToOne reference without @Audited annotation

      I have an annotated (with @Audited) entity class (lets say - class A) in which I am using ManyToOne reference to another class (lets named this class as B).

      For various reason, I do not want to mark class B as @Audited class, because B is a static dictionary class with milion of records, so duplications in the Audited table is no possible.

      For now there is exception that the B class must be marked as @Audited.

      Is there any way to implement such a configuration in present Envers version (1.2.1)? Is this feature planned?

      I see such a configuration to work like in the @Audited class (I mean in te historic version of this class A_AUD) I will have ManyToOne reference to the non-audited class B.

      Is there any workaround to solve this problem?

        • 1. Re: ManyToOne reference without @Audited annotation
          adamw

          Hello,

          this is unfortunately not currently possible - but I guess it's the most requested feature right now ;). So I'll try to add it soon - or maybe you would like to try?

          Adam

          • 2. Re: ManyToOne reference without @Audited annotation

            Adam, we are going to implement this feature and provide the patch as well.

            Related Jira issue: http://opensource.atlassian.com/projects/hibernate/browse/HHH-4010

            • 3. Re: ManyToOne reference without @Audited annotation
              adamw

              Great :)
              If you need any help, code pointers etc, let me know either here or via e-mail.

              Adam

              • 4. Re: ManyToOne reference without @Audited annotation

                patch to support ManyToOne reference is now available for download on http://opensource.atlassian.com/projects/hibernate/browse/HHH-4010

                Marcin

                • 5. Re: ManyToOne reference without @Audited annotation
                  varunmehta

                  Shouldn't the annotation @NotAudited on the @ManyToOne take care of it ?

                  class A {
                   B b;
                  
                   @ManyToOne
                   @JoinColumn(name = "a_b_id")
                   @NotAudited
                   getB() {
                   // bla bla
                   }
                  }


                  @NotAudited
                  When applied to a field, indicates that this field should not be audited.


                  I has the same use case and I applied these annotation and envers stopped complaining. I referred to this ticket;
                  http://opensource.atlassian.com/projects/hibernate/browse/HHH-3779

                  • 6. Re: ManyToOne reference without @Audited annotation
                    adamw

                    Hello,

                    thanks a lot! I'll apply it when I get some free time :)

                    Adam

                    • 7. Re: ManyToOne reference without @Audited annotation
                      varunmehta

                       

                      "varunmehta" wrote:
                      Shouldn't the annotation @NotAudited on the @ManyToOne take care of it ?


                      Answering my own question, yes and no.

                      Yes: Provided you don't want the relation to be audited
                      No: If you want the relation to be audited.

                      This is most important line to be understood.
                      If there is a need to have assiociation property audited, which target is not audited class/object, simply annotate such property

                      Means, if A is audited, B is not and in A you have;
                      @ManyToOne
                       @JoinColumn(name = "b_id")
                       getB() {
                       // bla bla
                       }


                      so if you want to audit the column b_id in A, then follow the solution mtatarski provided, if you are not interested in auditing the column at all, then use @NotAudited, but when you do that, fetching a.getB() will result in null, as the relation was never stored!

                      Hope that makes sense took me some time to figure out.

                      • 8. Re: ManyToOne reference without @Audited annotation
                        adamw

                        Applied, thanks a lot! The patch was really great :)
                        One small thing I changed is rename the "targetAuditMode" to "relationTargetAuditMode" to make it more clear what it means - I was a bit confused myself at the beginning.

                        Adam

                        • 9. Re: ManyToOne reference without @Audited annotation
                          varunmehta

                          Adam,

                          I tried the patch too, but it was misbehaving for composite Ids. Where can I download the applied patch code.

                          • 10. Re: ManyToOne reference without @Audited annotation
                            varunmehta

                            ok, I got the code from http://anonsvn.jboss.org/repos/hibernate/core/branches/envers-hibernate-3.3/

                            3 Test cases failed;

                            org.hibernate.envers.test.integration.primitive.PrimitiveAddDelete.testHistoryOfId1
                            org.hibernate.envers.test.integration.primitive.PrimitiveAddDelete.testRevisionsCount
                            org.hibernate.envers.test.integration.reventity.ExceptionListener.testTransactionRollback


                            Here is the stacktrace.

                            java.lang.NullPointerException
                             at org.hibernate.envers.test.integration.primitive.PrimitiveAddDelete.testHistoryOfId1(PrimitiveAddDelete.java:81)
                             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.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:607)
                             at org.testng.internal.Invoker.invokeMethod(Invoker.java:517)
                             at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:669)
                             at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:956)
                             at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:126)
                             at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:110)
                             at org.testng.TestRunner.runWorkers(TestRunner.java:759)
                             at org.testng.TestRunner.privateRun(TestRunner.java:592)
                             at org.testng.TestRunner.run(TestRunner.java:486)
                             at org.testng.SuiteRunner.runTest(SuiteRunner.java:332)
                             at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:327)
                             at org.testng.SuiteRunner.privateRun(SuiteRunner.java:299)
                             at org.testng.SuiteRunner.run(SuiteRunner.java:204)
                             at org.testng.TestNG.createAndRunSuiteRunners(TestNG.java:877)
                             at org.testng.TestNG.runSuitesLocally(TestNG.java:842)
                             at org.testng.TestNG.run(TestNG.java:751)
                             at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:73)
                             at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:124)
                            ------------------------------------------------------------
                            java.lang.AssertionError
                             at org.hibernate.envers.test.integration.primitive.PrimitiveAddDelete.testRevisionsCounts(PrimitiveAddDelete.java:73)
                             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.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:607)
                             at org.testng.internal.Invoker.invokeMethod(Invoker.java:517)
                             at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:669)
                             at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:956)
                             at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:126)
                             at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:110)
                             at org.testng.TestRunner.runWorkers(TestRunner.java:759)
                             at org.testng.TestRunner.privateRun(TestRunner.java:592)
                             at org.testng.TestRunner.run(TestRunner.java:486)
                             at org.testng.SuiteRunner.runTest(SuiteRunner.java:332)
                             at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:327)
                             at org.testng.SuiteRunner.privateRun(SuiteRunner.java:299)
                             at org.testng.SuiteRunner.run(SuiteRunner.java:204)
                             at org.testng.TestNG.createAndRunSuiteRunners(TestNG.java:877)
                             at org.testng.TestNG.runSuitesLocally(TestNG.java:842)
                             at org.testng.TestNG.run(TestNG.java:751)
                             at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:73)
                             at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:124)
                            ------------------------------------------------------------
                            javax.persistence.RollbackException: Error while commiting the transaction
                             at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:71)
                             at org.hibernate.envers.test.integration.reventity.ExceptionListener.testTransactionRollback(ExceptionListener.java:51)
                             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.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:607)
                             at org.testng.internal.Invoker.invokeMethod(Invoker.java:517)
                             at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:669)
                             at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:956)
                             at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:126)
                             at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:110)
                             at org.testng.TestRunner.runWorkers(TestRunner.java:759)
                             at org.testng.TestRunner.privateRun(TestRunner.java:592)
                             at org.testng.TestRunner.run(TestRunner.java:486)
                             at org.testng.SuiteRunner.runTest(SuiteRunner.java:332)
                             at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:327)
                             at org.testng.SuiteRunner.privateRun(SuiteRunner.java:299)
                             at org.testng.SuiteRunner.run(SuiteRunner.java:204)
                             at org.testng.TestNG.createAndRunSuiteRunners(TestNG.java:877)
                             at org.testng.TestNG.runSuitesLocally(TestNG.java:842)
                             at org.testng.TestNG.run(TestNG.java:751)
                             at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:73)
                             at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:124)
                            Caused by: org.hibernate.TransactionException: JDBC commit failed
                             at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:161)
                             at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
                             ... 23 more
                            Caused by: java.sql.SQLException: Can't call commit when autocommit=true
                             at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:930)
                             at com.mysql.jdbc.ConnectionImpl.commit(ConnectionImpl.java:1552)
                             at org.hibernate.transaction.JDBCTransaction.commitAndResetAutoCommit(JDBCTransaction.java:170)
                             at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:146)
                             ... 24 more


                            When I generated a jar out of this code, I get an error registering composite Ids;

                            IdMetadataGenerator:
                            // lines 96 - 105
                            
                             } else if (id_prop.isComposite()) {
                             // Embedded id
                            
                             Component id_component = (Component) id_prop.getValue();
                            
                             mapper = new EmbeddedIdMapper(getIdPropertyData(id_prop), id_component.getComponentClassName());
                             addIdProperties(rel_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), mapper, false);
                            
                             // null mapper - the mapping where already added the first time, now we only want to generate the xml
                             addIdProperties(orig_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), null, true);


                            And then the method, addIdProperties fails when checking propertyType instance of..

                            @SuppressWarnings({"unchecked"})
                             private void addIdProperties(Element parent, Iterator<Property> properties, SimpleMapperBuilder mapper, boolean key) {
                             while (properties.hasNext()) {
                             Property property = properties.next();
                             Type propertyType = property.getType();
                             if (!"_identifierMapper".equals(property.getName())) {
                             if (propertyType instanceof ImmutableType) {
                             // Last but one parameter: ids are always insertable
                             mainGenerator.getBasicMetadataGenerator().addBasic(parent,
                             getIdPersistentPropertyAuditingData(property),
                             property.getValue(), mapper, true, key);
                             } else {
                             throw new MappingException("Type not supported: " + propertyType.getClass().getName());
                             }
                             }
                             }
                             }


                            I'm going to try again, but let me know if you are already aware of the problem and have a solution.

                            • 11. Re: ManyToOne reference without @Audited annotation
                              varunmehta

                              My bad, damn should have checked my code before posting this issue. The test cases still fails;

                              Composite keys were failing cos I had marked one of them as

                              static


                              • 12. Re: ManyToOne reference without @Audited annotation
                                varunmehta

                                Ok I'm too sleepy working too late, it was a different code base I was testing on, works for primitive Objects marked for @Embeddable but not classes, will try adding new test cases.

                                • 13. Re: ManyToOne reference without @Audited annotation
                                  varunmehta

                                   

                                  "varunmehta" wrote:
                                  My bad, damn should have checked my code before posting this issue. The test cases still fails;

                                  Composite keys were failing cos I had marked one of them as
                                  static


                                  Did not work, I was looking at the wrong code base (older version of the envers jar), If you have Primitives as Composite Keys it works, but when you use classes they complain.

                                  Caused by: org.hibernate.MappingException: Type not supported: org.hibernate.type.ManyToOneType
                                   at org.hibernate.envers.configuration.metadata.IdMetadataGenerator.addIdProperties(IdMetadataGenerator.java:71)
                                   at org.hibernate.envers.configuration.metadata.IdMetadataGenerator.addId(IdMetadataGenerator.java:102)
                                   at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.generateFirstPass(AuditMetadataGenerator.java:329)
                                   at org.hibernate.envers.configuration.EntitiesConfigurator.configure(EntitiesConfigurator.java:91)
                                   at org.hibernate.envers.configuration.AuditConfiguration.<init>(AuditConfiguration.java:86)
                                   at org.hibernate.envers.configuration.AuditConfiguration.getFor(AuditConfiguration.java:99)
                                   at org.hibernate.envers.event.AuditEventListener.initialize(AuditEventListener.java:260)
                                   at org.hibernate.event.EventListeners$1.processListener(EventListeners.java:198)
                                   at org.hibernate.event.EventListeners.processListeners(EventListeners.java:181)
                                   at org.hibernate.event.EventListeners.initializeListeners(EventListeners.java:194)
                                   ... 41 more


                                  The mapping of my classes are such;

                                  @Entity
                                  public class Order {
                                   @Id
                                   private int orderId;
                                  }
                                  
                                  @Entity
                                  public class User {
                                   @Id
                                   private int userId;
                                  }
                                  
                                  @Entity
                                  public class Salesperson {
                                   @EmbeddedId
                                   private SalespersonPK salespersonPK;
                                  }
                                  
                                  @Embeddable
                                  public class SalespersonPK {
                                  @ManyToOne
                                   private Order order;
                                  
                                  @ManyToOne
                                   private User user;
                                  }


                                  So when a Composite key of two objects is used, it fails, Is this mapping valid (I believe so), or org.hibernate.MappingException: Type not supported: org.hibernate.type.ManyToOneType should be checked for ImmutableTypes. Please suggest.

                                  None of them are Audited for now, nor will I audit them, other classes are getting audited, but running the test cases causes the context load to fail.

                                  • 14. Re: ManyToOne reference without @Audited annotation
                                    varunmehta

                                    Adding this fixed the ManytoOneType issue

                                    if (!"_identifierMapper".equals(property.getName())) {
                                     if (propertyType instanceof ImmutableType) {
                                     // Last but one parameter: ids are always insertable
                                     mainGenerator.getBasicMetadataGenerator().addBasic(parent,
                                     getIdPersistentPropertyAuditingData(property),
                                     property.getValue(), mapper, true, key);
                                     } else if (propertyType instanceof EntityType) {
                                     // Last but one parameter: ids are always insertable
                                     mainGenerator.getBasicMetadataGenerator().addBasic(parent,
                                     getIdPersistentPropertyAuditingData(property),
                                     property.getValue(), mapper, true, key);
                                     } else {


                                    But this solution correct, if so let me know I'll provide it as a patch.

                                    1 2 Previous Next