Mapping collection inside container entity to one table


#1

I have the following class structure:

public class Container {

    private Set<Child> childs  = new HashSet<>();
}

public class Child {
    String name;
    String value;
    String param;
}

Because of Container class is going to be single in application (just wrapper on collections that may be updated), I would like to store it in one table, e.g.“childs” with columns

id | name | value | param
Is it possible to make such mapping in order to use Container when fetch or store it through hb session with corresponding updates to childs collection:

getSession().saveOrUpdate(container)
And if so, what mapping should be in that case?


#2

The Container entity is the parent.

That means the Child needs to have a FK back to its Parent.

So, the Container entity needs to be backed by a container table so that its PK is referenced by the Child table FK.

That’s how a one-to-many table relationship works.

For more details bout how to map this association, check out this article.


#3

Thanks for the reply!
I am still confused is it possible to map using one table. If we have ids fields in table. So container_id will always the same and child_id will be different and that’s what pk would be

container_id | child_id | name | value | param


#4

So, if there is no container table, is that value coming from some external system?

You cannot map an entity without having a table. Theoretically, you could map the Container entity to a View using an SQL query like this one:

CREATE OR REPLACE VIEW container_view AS 
select distinct container_id as id
from child

and the Container entity becomes:

@Entity
@Table(name = "container_view ")  
public class Container{
 
    @Id
    @Column(name = "id")
    private Long id; 
}

#5

You should not should @Table for an entity mapped on a view but @org.hibernate.annotations.Subselect
DDL generators (Hibernate Tools or JPA) with generate an incorrect “create table” statement if you use @Table.
You may also add @org.hibernate.annotations.Synchronize to specify which entities are behind the view (to avoid stale data and ensure correct refreshing).


#6

If you use hbm2ddl, then this is correct. However, Flyway is a much better alternative to hbm2ddl update and using @Table will work with other JPA providers while @Subselect will work only with Hibernate.


#7

With JPA schema export (EntityManagerFactoryBuilder.generateSchema()), @Table also generates a “create table” statement, and while using @Subselect even if Hibernate-specific, generateSchema() doesn’t generate anything and this is cleaner than generating something to be fixed later by hand.

Also I don’t see how any other tool how good it can be, can make the difference between @Table("SomeTable") and @Table("SomeView") without adding some additional info somewhere to avoid the generation of an unwanted “create table SomeView”…

JPA definitively lacks an “@View” annotation where we could also opt. add the Hibernate equiv. of @SQLInsert, @SQLUpdate, …


#8

As stated before, you don’t need to generate any schema with Hibernate. The hbm2ddl was added to ease testing, at least for the Hibernate ORM core.

In a production environment, you want incremental migration scripts anyway. That’s why FlywayDB is a much better choice. If you are mapping the entities to an existing schema, which is the right way to model your entities, then using @Table is just fine.

@Subselect was added to map an “entity” to an SQL query. Not necessarily a view.

More, this ViewTest works justs fine because even if Hibernate tries to recreate the @Table, the test does not fail since HBM2DDL exceptions are not causing execution stops.

So, you can still use that even to generate some intermediary update scripts that you are then customizing and handle them to FlywayDB.