Hibernate/Envers unable to read the mapped by attribute

左心房为你撑大大i 提交于 2019-12-21 09:29:34

问题


I am unable to implement many-to-many relation using join table (https://stackoverflow.com/a/7603036 & https://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Mapping_a_Join_Table_with_Additional_Columns). When I try to reproduce it persistence unit is unable to build EntityManagerFactory. It seems that Envers fails to read the mapped by attribute, although it looks good to me. What am I doing wrong? What is the right way™ to implement many-to-many relation with extra columns (and Envers)?

Product.java

@Entity
@Audited
public class Product extends UserModel {
...
    @OneToMany(mappedBy = "product", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    public List<ProductForm> forms = new ArrayList<ProductForm>();
...
}

Form.java

@Entity
@Audited
public class Form extends UserModel {
...
    @OneToMany(mappedBy = "form", fetch = FetchType.LAZY)
    public List<ProductForm> products = new ArrayList<ProductForm>();
...
}

ProductForm.java

@Entity
@Table(name = "Product_Form")
@IdClass(ProductForm.ProductFormId.class)
public class ProductForm {
    @Id
    @JoinColumn(name = "product_id")
    @ManyToOne
    public Product product;

    @Id
    @JoinColumn(name = "form_id")
    @ManyToOne
    public Form form;

    public ProductForm(Product product, Form form) {
        this.product = product;
        this.form = form;
    }

    @Embeddable
    @SuppressWarnings("serial")
    public class ProductFormId implements Serializable {
        @Column(name = "product_id")
        public Long product;

        @Column(name = "form_id")
        public Long form;
    }
}

Stack trace

play.api.UnexpectedException: Unexpected exception[PersistenceException: [PersistenceUnit: defaultPersistenceUnit] Unable to build EntityManagerFactory]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:142) ~[play_2.10-2.1.1.jar:2.1.1]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:106) ~[play_2.10-2.1.1.jar:2.1.1]
    at scala.Option.map(Option.scala:145) ~[scala-library.jar:na]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:106) ~[play_2.10-2.1.1.jar:2.1.1]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:104) ~[play_2.10-2.1.1.jar:2.1.1]
    at scala.util.Either$RightProjection.flatMap(Either.scala:523) [scala-library.jar:na]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: defaultPersistenceUnit] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:930) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:904) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:72) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:63) ~[hibernate-jpa-2.0-api-1.0.1.Final.jar:1.0.1.Final]
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:47) ~[hibernate-jpa-2.0-api-1.0.1.Final.jar:1.0.1.Final]
    at play.db.jpa.JPAPlugin.onStart(JPAPlugin.java:35) ~[play-java-jpa_2.10-2.1.1.jar:2.1.1]
Caused by: org.hibernate.MappingException: Unable to read the mapped by attribute for products in models.ProductForm!
    at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.getMappedBy(CollectionMetadataGenerator.java:642) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.addOneToManyAttached(CollectionMetadataGenerator.java:187) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.addCollection(CollectionMetadataGenerator.java:169) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addValueInSecondPass(AuditMetadataGenerator.java:223) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addValue(AuditMetadataGenerator.java:245) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addProperties(AuditMetadataGenerator.java:258) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]

PS I tried to add @AuditMappedBy(mappedBy = "product") to Product:

play.api.UnexpectedException: Unexpected exception[PersistenceException: [PersistenceUnit: defaultPersistenceUnit] Unable to build EntityManagerFactory]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:142) ~[play_2.10-2.1.1.jar:2.1.1]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:106) ~[play_2.10-2.1.1.jar:2.1.1]
    at scala.Option.map(Option.scala:145) ~[scala-library.jar:na]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:106) ~[play_2.10-2.1.1.jar:2.1.1]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:104) ~[play_2.10-2.1.1.jar:2.1.1]
    at scala.util.Either$RightProjection.flatMap(Either.scala:523) [scala-library.jar:na]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: defaultPersistenceUnit] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:930) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:904) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:72) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:63) ~[hibernate-jpa-2.0-api-1.0.1.Final.jar:1.0.1.Final]
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:47) ~[hibernate-jpa-2.0-api-1.0.1.Final.jar:1.0.1.Final]
    at play.db.jpa.JPAPlugin.onStart(JPAPlugin.java:35) ~[play-java-jpa_2.10-2.1.1.jar:2.1.1]
Caused by: org.hibernate.MappingException: @AuditMappedBy points to a property that doesn't exist: models.ProductForm.product
    at org.hibernate.envers.configuration.ClassesAuditingData.forcePropertyInsertable(ClassesAuditingData.java:84) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.ClassesAuditingData.updateCalculatedFields(ClassesAuditingData.java:70) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.EntitiesConfigurator.configure(EntitiesConfigurator.java:85) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.AuditConfiguration.<init>(AuditConfiguration.java:114) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.AuditConfiguration.getFor(AuditConfiguration.java:164) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.event.EnversIntegrator.integrate(EnversIntegrator.java:64) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]

Edit

When I add @Audited to ProductForm is still get same error, below is the newest stack trace.

play.api.UnexpectedException: Unexpected exception[PersistenceException: [PersistenceUnit: defaultPersistenceUnit] Unable to build EntityManagerFactory]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:142) ~[play_2.10-2.1.1.jar:2.1.1]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:106) ~[play_2.10-2.1.1.jar:2.1.1]
    at scala.Option.map(Option.scala:145) ~[scala-library.jar:na]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:106) ~[play_2.10-2.1.1.jar:2.1.1]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:104) ~[play_2.10-2.1.1.jar:2.1.1]
    at scala.util.Either$RightProjection.flatMap(Either.scala:523) [scala-library.jar:na]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: defaultPersistenceUnit] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:930) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:904) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:72) ~[hibernate-entitymanager-4.2.0.Final.jar:4.2.0.Final]
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:63) ~[hibernate-jpa-2.0-api-1.0.1.Final.jar:1.0.1.Final]
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:47) ~[hibernate-jpa-2.0-api-1.0.1.Final.jar:1.0.1.Final]
    at play.db.jpa.JPAPlugin.onStart(JPAPlugin.java:35) ~[play-java-jpa_2.10-2.1.1.jar:2.1.1]
Caused by: org.hibernate.MappingException: Unable to read the mapped by attribute for products in models.ProductForm!
    at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.getMappedBy(CollectionMetadataGenerator.java:642) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.addOneToManyAttached(CollectionMetadataGenerator.java:187) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.CollectionMetadataGenerator.addCollection(CollectionMetadataGenerator.java:169) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addValueInSecondPass(AuditMetadataGenerator.java:223) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addValue(AuditMetadataGenerator.java:245) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]
    at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.addProperties(AuditMetadataGenerator.java:258) ~[hibernate-envers-4.2.0.Final.jar:4.2.0.Final]

回答1:


If you problem is caused by Composite keys, then update your hibernate version to 5.2.2 if possible. Because this bug was fixed in this version.

See: https://hibernate.atlassian.net/browse/HHH-7625




回答2:


What you're going for is what I've seen called an "association entity". I have a few of them and in general I recommend not to use composite ids, since there tend to be lots of edge cases around them.

Instead give the association entity its own id, place a unique index on the pair of foreign keys, and then add associations for the two associated entities (and leave out their ids). Here's a stripped down example:

@Entity
class A {
   @Id
   private Integer aId;

   @OneToMany(mappedBy="a")
   private AtoB aToB;
}

@Entity
class B {
   @Id
   private Integer bId;

   @ManyToOne
   @JoinColumn(name="b")
   private AtoB aToB;
}

@Entity
class AtoB {

  @Id
  private Integer aToBId;

  @ManyToOne
  @JoinColumn(name="aId")
  private A a;

  @OneToMany(mappedBy="aToB")
  private B b;
}

Does this make sense?




回答3:


As far as Hibernate is concerned, you have three entities with one-to-many associations.

So making the "join" entity audited should do the trick: add @Audited to ProductForm.



来源:https://stackoverflow.com/questions/16287007/hibernate-envers-unable-to-read-the-mapped-by-attribute

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!