Embeddable and ElementCollection nesting
Asked Answered
B

2

16

I have fairly typical scenario where there is a main @Entity and everything inside him is embeddable (so everything inside doesn't make sense without the parent). Now JPA 2.0 is blocking me to nest a @ElementCollection inside a @Embeddable defined in another @ElementCollection:

JSR-317 2.6 Collections of Embeddable Classes and Basic Types An embeddable class (including an embeddable class within another embeddable class) that is contained within an element collection must not contain an element collection, nor may it contain a relationship to an entity other than a many-to-one or one-to-one relationship

Now the question is: why is this? A simple example:

@Entity
public class Tournament {
    @Id
    Long id;

    @ElementCollection
    @CollectionTable
    private List<Edition>;
}

@Embeddable
public class Edition {

    @ElementCollection
    @CollectionTable
    private List<Round>
}

@Embeddable
public class Round {

    blabla;
}

What's the problem having this? This is just an example, you could define Round and Edition as Entity and solve the problem, but in my case for a number of reasons I need to enforce that something very nested doesn't make sense without his parent.

Why JPA 2.0 has to stop me doing this?

Bowe answered 2/3, 2014 at 10:24 Comment(0)
T
22

Your situation violates the specification element you pasted in:

Edition is itself @Embeddable, and contains an element collection of Round, and thus:

An embeddable class (Edition) that is contained within an element collection (Tournament.editions) must not contain an element collection (Edition.rounds).

As to why you can't do this - if you look at the examples from http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection then you'll see that the child (Edition) would be mapped with only a FK back to the owner (Tournament.id) without an ID column of its own - on the grounds that as a Weak entity, it has no ID of its own, and is only defined by reference to the ID of the Tournament.

Taking the Round, if that too is a weak entity, then it should be defined by FK reference to the Edition - but we already said that has no ID of its own, so you can't map this in the DB without adding an ID to the Edition - at which point it would be an entity in its own right, and not be simply @Embeddable.

Looking at the Wikipedia example from the comment below - http://en.wikipedia.org/wiki/Weak_entity - the examples of weak entities there are OrderNumber, CustomerNumber etc - things which only ever make any sense when embedded in another object.

You can still have entities which have parent mappings (i.e. a Tournament reference on the Edition) and/or bi-directional references. You can force the parent to be defined on the Edition with a nullable=false attribute on the @ManyToOne annotation, and thus enforce the requirements of your model.

Traylor answered 2/3, 2014 at 11:29 Comment(2)
As I wrote in the question, it is needed by the model: it shouldn't be possible to load an Edition without his Tournament, and an Edition cannot exists if you don't have a Tournament first. It's the notion of Weak Entity that is well known in ER diagrams but seems to be not well implemented in JPA. I was just trying to understand why in JPA you cannot have more nested embeddable elementcollections (maybe there is an implementation problem?), that is a common way of describing things in the real world.Bowe
Thanks for your detailed answer. At the end I realised Embeddable does not map exactly with the idea of weak entity. A weak entity should have a composite primary key composed by the foreign key to the parent entity + his own id, and this is not the case for a Embeddable object. So I think the last option you gave is the most reasonable, even though I thought there was something more direct to map a weak entity, but I was wrong.Bowe
S
0

@Embedded vs @ElementCollection in JPA

@Embedded

  1. Purpose:

    • Used for embedding a single object within an entity.
    • Represents a has-a relationship.
  2. Cardinality:

    • One-to-one relationship between the entity and the embedded object.
  3. Database Representation:

    • Columns of the embedded object are included in the same table as the owning entity.
  4. Usage:

    @Entity
    public class Employee {
        @Id
        private Long id;
    
        @Embedded
        private Address address;
    }
    
    @Embeddable
    public class Address {
        private String street;
        private String city;
    }
    
  5. Data Structure:

    • Typically used with a single object, not a collection.
  6. Lifecycle:

    • The embedded object's lifecycle is bound to the owning entity.
  7. Performance:

    • Generally good as all data is in a single table.

@ElementCollection

  1. Purpose:

    • Used for collecting simple types or embeddable objects within an entity.
    • Represents a has-many relationship for simple types or embeddables.
  2. Cardinality:

    • One-to-many relationship between the entity and the collection elements.
  3. Database Representation:

    • Creates a separate table for the collection elements.
    • The new table has a foreign key referencing the owning entity's table.
  4. Usage:

    @Entity
    public class Employee {
        @Id
        private Long id;
    
        @ElementCollection
        private List<String> phoneNumbers;
    
        @ElementCollection
        private Set<Address> addresses;
    }
    
    @Embeddable
    public class Address {
        private String street;
        private String city;
    }
    
  5. Data Structure:

    • Used with collections (List, Set, Map).
  6. Lifecycle:

    • The collection elements' lifecycle is bound to the owning entity.
  7. Performance:

    • Can have performance implications for large collections due to separate table access.

Key Differences

  1. Multiplicity:

    • @Embedded is for a single object, @ElementCollection is for multiple objects.
  2. Table Structure:

    • @Embedded adds columns to the existing table, @ElementCollection creates a new table.
  3. Complexity:

    • @Embedded is simpler and more performant for single objects, @ElementCollection offers more flexibility for collections.
  4. Query Joins:

    • @ElementCollection typically requires a join when querying, @Embedded doesn't.
  5. Use Cases:

    • Use @Embedded for composing entities with value objects.
    • Use @ElementCollection for simple collections of basic types or embeddables.

Choose based on your data model requirements and performance considerations.

Shoplifter answered 2/8, 2024 at 10:14 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.