Question

I am trying to add a relationship "OneToMany" to a database i am creating to test if ObjectDB is any good for me.

what I have tried so far:

@Entity
public class Parent {
    @Id
    private int parentID;
    private int childFK;
    Set<Child> children;

    public Parent(int p,int c) {
    this.parentID = p;
    this.childFK = c;
    }

    @OneToMany(orphanRemoval=true)
    @JoinColumn(name="childFK")
    public Set<Child> getChildren(){
        return childern;
    }
}

This child class is:

@Entity
public class Child {
    @Id
    private int childID;
    private String name;

    public Child(int c,String n) {
    this.childID = c;
    this.name = n;
    }
}

My main method is:

   EntityManagerFactory emf = Persistence.createEntityManagerFactory("$objectdb/db/test.odb");
   EntityManager em = emf.createEntityManager();

   em.getTransaction().begin();

   Parent p = new Parent(01,02);
   em.persist(p);
   Child c = new Child(02,"bob");
   em.persist(c);

   em.getTransaction().commit();

This creates the database no problem but no relationships exist. This is the was the documentations states how to do it.

I have also tried adding the the actual instance of child to the database. This somewhat works as it then knows there is an instance of the database available but it then does not know how to use it.

I have tried the query:

 SELECT p.getChildren() FROM Parent p

This just returns no such method getChildren().

Any ideas?

Was it helpful?

Solution

There are two problems in your test. After fixing these errors the relationship between the parent and the child is created as expected.

The first problem, in JPA you can use field access or property access, but mixing them is not allowed. If you annotate a field with @Id then your are using field access. In that case, other annotations should also be on fields rather than on property methods.

Accordingly your Parent class should be defined as:

@Entity
public static class Parent {
    @Id
    private int parentID;
    private int childFK;
    @OneToMany(orphanRemoval=true)
    // @JoinColumn(name="childFK") ignored by ObjectDB
    Set<Child> children;

    public Parent(int p,int c) {
        this.parentID = p;
        this.childFK = c;
    }

    public Set<Child> getChildren(){
        return children;
    }
}

The second problem is that the main method persists two objects, a parent and a child, but without connecting them. You have to add a line of code for connecting these two objects:

    EntityManager em = emf.createEntityManager();

    em.getTransaction().begin();

    Parent p = new Parent(01,02);
    em.persist(p);
    Child c = new Child(02,"bob");
    em.persist(c);
    p.children = Collections.singleton(c); // connect the child to the parent

    em.getTransaction().commit();

After running the test with these fixes an ObjectDB database is created with the relationship.

OTHER TIPS

I tried the solution p.children = Collections.singleton(c) but it won't work for me. Here is my take on the problem ... lets just use the Parent and Class Objects as with the example above.

@Entity
public class Parent { 
  @Id
  private int parentID;
  private int childFK;

  Set<Child> children;

  public Parent(int p,int c) {
    this.parentID = p;
    this.childFK = c;
  }

  . . .

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  @JoinColumn(name="childFK")
  public Set<Child> getChildren(){
    return childern;
  }
  public void setChildren(Set<Child> children) {
    this.children = children;
  }
}


@Entity
public class Child {
  @Id
  private int childID;      
  private String name;
  private int parentID;

  public Child(int c,String n, int p) {
    this.childID = c;
    this.name = n;
    this.parentID = p;
  }
}

In real world scenario, you need to get childID value from some source in this case let's just get an id from the Child class.

public int childLastID(EntityManager em){
  TypedQuery<Child> query = em.createQuery("SELECT c FROM Child c order by i.childID 
                                            DESC", Child.class);

  List<Child> chldx = query.setFirstResult(0).setMaxResults(1).getResultList();

  if(chldx == null) return 100;  // In case your Child is new and empty 
                                 // lets start with 100

  return (chldx.get(0)).getId();                                    
}

Now let's populate Those Parent and Child Class ...

EntityManagerFactory emf = Persistence.createEntityManagerFactory("...");            
EntityManager em = emf.createEntityManager();

int ix = childLastID(em);

em.getTransaction().begin();
Parent p = new Parent(01, ++ix); // increment the last ID to make sure it's unique


Set<Child> cset = new HashSet<Child>();   
Child c1 = new Child(ix,"bob", 01);
cset.add(c1);

Child c2 = new Child(++ix,"beb", 01);
cset.add(c2);

Child c3 = new Child(++ix, "bib", 01);
cset.add(c3)


p.setChildren(cset);
em.persist(p)    

em.getTransaction().commit();

Now, the collection of Child c1 ... c3 will be persisted on the Parent class. I incremented ++ix on c2 and c3 because they need to have a unique id on the Child class. I added a parentID on the Child class to serve as a reference for both the Parent and the Child class.

I use FetchType.EAGER so that when the Parent is retrieved those Child references will also be retrieved.

Also an ID for entity classes should be of type long not int, so just change those int with long primitive type.

Hope this will help ...

Nelson Deogracias

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top