How to map many-to-many List in Hibernate with a L

2019-03-27 12:12发布

问题:

I would like to map a many-to-many in Hibernate using a link table. I have two classes, Parent and Child class, for example:

public class Parent{

private List<Child> _children;

//...getters and setters
}

I use a link table (link_table) with three columns link_id, parent_id, and child_id. The database is SQL server and id types are uniqueidentifier. So, I usually use guid for the id fields.

How can you implement this using the <list /> tag if this is the correct tag to use? Do you know of any good documentation to accomplish this?

I am currently getting a ConstraintViolationException but have not been able to find any good documentation or examples of this.

I think a main issue is: how to specify the link_id to be automatically generated in the link table.

回答1:

I don't think that it is possible (or necessary) to add a link_id primary key to the join table. The join table will usually consist of the primary keys of the two participating tables.

Using XML you will need syntax like this:

 <class name="Parent">
    ....
    <list name="children" table="link_table">
    <key column="parent_id"/>
    <many-to-many column="child_id"
        class="Children"/>
    </list>
    ...
 </class>

<class name="Child">
...
<list name="parents" inverse="true" table="link_table">
    <key column="child_id"/>
    <many-to-many column="parent_id"
        class="Parent"/>
</list>
...
</class>

Although I find annotations better to use.



回答2:

I do this using annotations, specifically @ManyToMany and @JoinTable:

Hibernate Docs:

@Entity
public class Employer implements Serializable {
    @ManyToMany(
        targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,
        cascade={CascadeType.PERSIST, CascadeType.MERGE}
    )
    @JoinTable(
        name="EMPLOYER_EMPLOYEE",
        joinColumns=@JoinColumn(name="EMPER_ID"),
        inverseJoinColumns=@JoinColumn(name="EMPEE_ID")
    )
    public Collection getEmployees() {
        return employees;
    }
}


@Entity
public class Employee implements Serializable {
    @ManyToMany(
        cascade = {CascadeType.PERSIST, CascadeType.MERGE},
        mappedBy = "employees",
        targetEntity = Employer.class
    )
    public Collection getEmployers() {
        return employers;
    }
}


回答3:

I am not sure that you can pull this off easily for an existing database with existing data. Hibernate is usually better off defining its own data schema the first time you connect...

I've only pulled off many-to-many with annotations, but I think the hibernate documentation offers XML based examples: link text



回答4:

I found a very good blog online which gives 2 ways to add additional fields to the many to many mapped hibernate column. Traditionally we expect the many to many mapping to give a new table will FK's of tables mapped. But there are ways to tweak that and add more fields/column to this joined table.

This joined table may contain a PK or may contain some extra fields without PK. See this blog for exact implementation See Here

And as per your example, you need an extra PK in the table so you declare a new table ParentChildren and declare your primary key as linkId. I am showing just the annoated parentchildren class, as annotations for many to many mapping in parent and children class can be referenced from post above.

@Entity
@Table(name = "parent_children")
public class ParentChildren{
    @Id @GeneratedValue
    private long linkId;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "parent_id") 
    private Parent parent;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "children_id) 
    private Children children;

    // additional fields if you want
    private boolean activated;

    //getters and setters
    }
}

So this will create a mapping table which has linkId as primary key and parent_id and children_id as Foreign Key. Just be clear on why you want a link_id separately as primary key and how you are going to use it.