Archimedes Trajano
Archimedes Trajano

Reputation: 41610

How do you to create a one to many relationship in JPA with no JoinTables?

I am trying to create a @OneToMany relationship in JPA using the following table structure.

+----------------+
| CATALOG        |
+----------------+
| catalogId : PK |
| name           |
+----------------+
      |
+----------------+
| PRODUCT        |
+----------------+
| productId : PK |
| name           |
| catalogId : FK |
+----------------+

I have defined the classes as

@Entity
public class Catalog {
    @Id
    @GeneratedValue
    long catalogId;

    @OneToMany(cascade = CascadeType.ALL, 
               orphanRemoval = true, fetch = FetchType.LAZY)
    @JoinColumn(name = "catalogId", 
               nullable = false, insertable = true, updatable = true)
    Set<Product> products = new HashSet<>();

    String name;
}

@Entity
public class Product {
    @Id
    @GeneratedValue
    long productId;

    String name;
}

However, when I try to persist the catalog object, EclipseLink does not put in the catalogId value as expected and I get a SQL constraint violation that there is a null.

Also, I don't need nor want a @ManyToOne on the Product end.

The persistence code:

final Catalog catalog = new Catalog();
catalog.name = text;
final Product p = new Product();
p.name = text;
catalog.products.add(p);
em.persist(catalog);

The stack trace:

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Column 'CATALOGID'  cannot accept a NULL value.
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1367)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1295)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1301)
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:866)
    at net.trajano.maven_jee6.ws_mdb_ejb_web.TextMessages.putText(TextMessages.java:61)

Upvotes: 3

Views: 4866

Answers (3)

artaxerxe
artaxerxe

Reputation: 6421

I think it is due to the lack of @GeneratedValue annotation (with Postgres). From my experience, with Postgres, your annotating does not work. You need to specify the @SequenceGenerator and @GeneratedValue. Here's an example:



    @SequenceGenerator(name = "lan_generator", sequenceName = "lan_pkey_seq")
    @Id
    @GeneratedValue(generator = "lan_generator")
    @Column(name="id", unique=true, nullable=false)
    private Integer id;

If you are working with other databases, try to deal with yours. Anyway, at the giveb link, you have a possible solution when you are working with MySQL. Probably it will work also with your "in-memory derby instance".

How to annotate MYSQL autoincrement field with JPA annotations

Upvotes: 1

Affe
Affe

Reputation: 47994

When you give ownership of a column on one table, Product, to a different entity, Catalog, that column is going to be updated and maintained as part of persisting Catalog, not as part of persisting Product. The framework is going to create a product, but then because the FK column is "owned" by a different entity, it's going to populate that with a separate update statement that is generated when the Catalog is persisted. You need to either make the column nullable or put ownership of the column on the same entity that maps the table.

Upvotes: 7

Pramod Kumar
Pramod Kumar

Reputation: 8014

Make product class like this and try again -

@Entity
public class Product {
    @Id
    @GeneratedValue
    long productId;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "catalogId", updatable = false, insertable = false, nullable=false)  
    private Catalog  catalog ;

    String name;
}

Upvotes: 0

Related Questions