In my project I have the classes reported below, with a bidirectional relationship mapping. When I try to read an object of type DataProviderImpl through JPA I got the following exception:
org.apache.openjpa.persistence.ArgumentException: Field "persistence.entity.DataProviderImpl.methods" cannot declare that it is mapped by another field. Its mapping strategy( org.apache.openjpa.jdbc.meta.strats.HandlerCollectionTableFieldStrategy) does not support mapping by another field.
I have already checked other questions, but nothing seems to apply in my case. Any hints? Thank you in advance!
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="DataProvider" transaction-type="JTA"> <!-- transaction-type="RESOURCE_LOCAL" info at: http://tomee.apache.org/jpa-concepts.html -->
<jta-data-source>
osgi:service/jdbc/mysqlPoolXAds
</jta-data-source>
<non-jta-data-source>
osgi:service/jdbc/mysqlds
</non-jta-data-source>
<class>persistence.entity.DataProviderImpl</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
<persistence-unit name="RestMethod" transaction-type="JTA"> <!-- transaction-type="RESOURCE_LOCAL" info at: http://tomee.apache.org/jpa-concepts.html -->
<jta-data-source>
osgi:service/jdbc/mysqlPoolXAds
</jta-data-source>
<non-jta-data-source>
osgi:service/jdbc/mysqlds
</non-jta-data-source>
<class>persistence.entity.RestMethodImpl</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
@Entity(name = "DataProvider")
public class DataProviderImpl implements DataProvider {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
// ...
@OneToMany(fetch = FetchType.LAZY, mappedBy="dataProvider")
private List<RestMethod> methods;
public DataProviderImpl() {
super();
this.id = 0;
}
@Override
public int getId() {
return id;
}
@Override
public void setId(int id) {
this.id = id;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public List<RestMethod> getMethods() {
return methods;
}
@Override
public void setMethods(List<RestMethod> methods) {
this.methods = methods;
}
}
public interface DataProvider {
public int getId();
public void setId(int id);
public String getName();
public void setName(String name);
public List<RestMethod> getMethods();
public void setMethods(List<RestMethod> methods);
}
@Entity(name = "RestMethod")
public class RestMethodImpl implements RestMethod {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String nickname;
// ...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="dataProviderId")
private DataProvider dataProvider;
public RestMethodImpl() {
super();
this.id = 0;
}
@Override
public int getId() {
return id;
}
@Override
public void setId(int id) {
this.id = id;
}
@Override
public String getNickname() {
return nickname;
}
@Override
public void setNickname(String nickname) {
this.nickname = nickname;
}
@Override
public DataProvider getDataProvider() {
return dataProvider;
}
@Override
public void setDataProvider(DataProvider dataProvider) {
this.dataProvider = dataProvider;
}
}
public interface RestMethod {
public int getId();
public void setId(int id);
public String getNickname();
public void setNickname(String nickname);
public DataProvider getDataProvider();
public void setDataProvider(DataProvider dataProvider);
}
JPA One-To-Many Mapping The One-To-Many mapping comes into the category of collection-valued association where an entity is associated with a collection of other entities. Hence, in this type of association the instance of one entity can be mapped with any number of instances of another entity.
The @OneToMany and @ManyToOne JPA annotation are used to link one-to-many bidirectional entity mapping. Unidirectional → In this type of association, only the source entity has a relationship field that refers to the target entity.
The most appropriate way to implement JPA/Hibernate One To Many mapping is unidirectional Many-to-One association with @ManyToOne. You can read Vlad Mihalcea’s article for more details. We’re gonna create a Spring project from scratch, then we implement JPA/Hibernate One to Many Mapping with tutorials and comments table as following:
The One-To-Many mapping comes into the category of collection-valued association where an entity is associated with a collection of other entities. Hence, in this type of association the instance of one entity can be mapped with any number of instances of another entity.
Assuming that you used import statements from javax.persistence
your mapping annotations should definitely use the extra argument targetEntity=...
as otherwise the Object Relational Mapper can not exactly determine which class is to be instantiated for the given interface type, e.g., RestMethod
. So your mappings would be:
@Entity(name = "DataProvider")
public class DataProviderImpl implements DataProvider {
// ...
@OneToMany(targetEntity=RestMethodImpl.class, fetch = FetchType.LAZY, mappedBy="dataProvider")
private List<RestMethod> methods;
and accordingly:
@Entity(name = "RestMethod")
public class RestMethodImpl implements RestMethod {
// ...
@ManyToOne(targetEntity=DataProviderImpl.class, fetch = FetchType.LAZY)
@JoinColumn(name="dataProviderId")
private DataProvider dataProvider;
I don't know if this helps out in your case but certainly you should try to adjust your code with this extra information for the JPA mapper.
I just spotted another problem with your given persistence.xml
. You should have both classes (DataProviderImpl
and RestMethodImpl
) within the same persistence-unit
block, as the entity context build from your configuration must know about both classes to inflict a correct mapping strategy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With