Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA OneToMany mapping exception: Field XXX cannot declare that it is mapped by another field

Tags:

java

jpa

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);
}
like image 479
DocDbg Avatar asked Jan 16 '15 13:01

DocDbg


People also ask

What is one-to-many mapping in JPA?

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.

What is @OneToMany and @manytoone annotation in JPA?

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.

How to implement JPA/hibernate one to many mapping?

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:

What is one-to-many mapping in Salesforce?

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.


1 Answers

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.

like image 137
MWiesner Avatar answered Oct 13 '22 01:10

MWiesner