Why OneToMany relationships persist across multiple rows in a database

I have a hibernation entity class

public class MyComplexClass implements  Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    String name;
    int number;
    @ElementCollection
    Map<String,String> myMap;

    @ManyToOne
    Simple simple;

    public MyComplexClass(String name, int number, Map<String,String> myMap) {
        this.name = name;
        this.port = number;
        this.myMap = myMap;
    }

    public MyComplexClass() {
        // TODO Auto-generated constructor stub
    }

    public void setName(String name) {
        this.name = name;

    }

    public String getName() {
        return name;
    }

    public void setNumber(int number) {
        this.port = number;
    }

    public int getPort() {
        return port;
    }

    public void setMyMap(Map<String,String> myMap) {
        this.myMap = myMap;
    }

    public Map<String,String> getMyMap() {
        return this.myMap;
    }


    public Simple getSimple() {
        return this.simple;
    }

      

And in the simple class I have a display of the form

    @Entity
    @Table(name = "Simple")


    public class Simple  implements Comparable<Simple>, Serializable {
    @JsonProperty
    @OneToMany(mappedBy="simple",fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    Set<MyComplexClass> myComplexClass;

    public void setMyComplexClass(List<MyComplexClass> myComplexClass) {
        this.myComplexClass = myComplexClass;
    }

    public List<MyComplexClass> getMyComplexClass() {
        return this.myComplexClass;
    }

      

Somewhere in the system I am setting the values ​​as

Map<String, String> myMap = new HashMap<String,String>();
myMap.put("value","value");
MyComplexClass myComplexClass = new MyComplexclass("a", 123, myMap)
Set<MyComplexClass> myComplexClassList = new HashSet<MyComplexClass>();
myComplexClassList.add(myComplexClassList)
simple.setMyComplexClass(myComplexClassList);
myComplexClass.setSimple(simple);
// save to the database
dao.save(simple);

      

This is stored in a multi-row database for my complex class with the same foreign key for simple classes

 Table: MyComplexClass
    id  name number simple_id
     1  abc   234    1
     2  abc   234    1
     3  abc   234    1
     4  abc   234    1
     5  abc   234    1
     6  xyz   432    2
     7  xyz   432    2
     8  xyz   432    2

      

What did I miss? The identifier for all of these strings is different in that it makes me think they have been initialized multiple times in the code. But this is not the case. Why do they have different records? I am using AKKA actors, maybe this is the reason?

Based on various similar problems. I modified the collection as a set and also added a compareTo method as follows

public int compareTo(MyComplexClass o) {
        if (o == null) {
            return 1;
        }

        if (this.getName().equals(o.getName()) && this.getNumber() == o.getPort()) {
            return 0;
        }
        return (int) (id - o.id);
    }

      

+3


source to share


2 answers


I would vote to close this example, which does not compile and is not complete if possible, but since it has the bounty I cannot. You are referencing a dao object for which you are not using source. You call doa.save, is it a Spring question? Otherwise there is nothing wrong with your entities, it all works fine for me.

public class JPAExample {    
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistence");
        EntityManager em = emf.createEntityManager();
        try {
            EntityTransaction tx = em.getTransaction();
            tx.begin();
            Simple simple = new Simple();
            Map<String, String> myMap = new HashMap<String,String>();
            myMap.put("value","value");
            MyComplexClass myComplexClass = new MyComplexClass("a", 123, myMap);
            Set<MyComplexClass> myComplexClassList = new HashSet<MyComplexClass>();
            myComplexClassList.add(myComplexClass);
            simple.setMyComplexClass(myComplexClassList);
            myComplexClass.setSimple(simple);
            // save to the database
            em.persist(simple);
            tx.commit();
        } finally {
            emf.close();
        }
    }
}

      

Simple.class

@Entity
@Table(name = "Simple")
public class Simple implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id;
    //    @JsonProperty
    @OneToMany(mappedBy = "simple", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    Set<MyComplexClass> myComplexClass;
    public void setMyComplexClass(Set<MyComplexClass> myComplexClass) {
        this.myComplexClass = myComplexClass;
    }
    public Set<MyComplexClass> getMyComplexClass() {
        return this.myComplexClass;
    }
}

      

MyComplexClass



@Entity
@Table(name="MyComplexClass")
public class MyComplexClass implements  Serializable {
    private static final long serialVersionUID = 1L;
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id;
    String name;
    int number;
    @ElementCollection
    Map<String,String> myMap;
    @ManyToOne
    Simple simple;
    public MyComplexClass(String name, int number, Map<String,String> myMap) {
        this.name = name;
        this.myMap = myMap;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setMyMap(Map<String,String> myMap) {
        this.myMap = myMap;
    }
    public Map<String,String> getMyMap() {
        return this.myMap;
    }
    public Simple getSimple() {
        return this.simple;
    }
    public void setSimple(Simple simple ) {
        this.simple = simple;
    }
}

      

Produces the following output ...

Hibernate: create table MyComplexClass (id bigint generated by default as identity (start with 1), name varchar(255), number integer not null, simple_id bigint, primary key (id))
Hibernate: create table MyComplexClass_myMap (MyComplexClass_id bigint not null, myMap varchar(255), myMap_KEY varchar(255), primary key (MyComplexClass_id, myMap_KEY))
Hibernate: create table Simple (id bigint generated by default as identity (start with 1), primary key (id))
Hibernate: alter table MyComplexClass add constraint FK_qlkwvh7xyrn3udhnrn40fl6f8 foreign key (simple_id) references Simple
Hibernate: alter table MyComplexClass_myMap add constraint FK_qp5xa90y7pk94lb64kvt62589 foreign key (MyComplexClass_id) references MyComplexClass
Jun 12, 2017 10:06:56 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: insert into Simple (id) values (default)
Hibernate: insert into MyComplexClass (id, name, number, simple_id) values (default, ?, ?, ?)
Hibernate: insert into MyComplexClass_myMap (MyComplexClass_id, myMap_KEY, myMap) values (?, ?, ?)
Jun 12, 2017 10:06:56 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH000030: Cleaning up connection pool [jdbc:hsqldb:mem:standalone]

      

Which shows only one row inserted into the MyComplexClass table.

You can copy this code and use it to find out what is wrong with your code.

0


source


Since you are using a hash-based collection Set

, you must override equals

it hashcode

in your organization as well MyComplexClass

.

From the docs



You must override the equals () and hashCode () methods if you: intend to put instances of constant classes in a Set (the recommended way to represent multivalued associations); and also intend to re-bind individual instances

Overriding equals

and hashcode

should fix your problem.

0


source







All Articles