I am having some trouble understanding the difference between #OneToMany and #ManyToMany. When I use #OneToMany it defaults to create a JoinTable and if you add the mappedBy attribute you will have bidirectional relationship between two entities.
I have a Question that may belong to many Categories, and one Category may belong to many Questions. I don't understand if I should use #ManyToMany or #OneToMany because for me it seems exactly the same thing, but it is probably not.
Could somebody explain it?
Well, the difference is in the design you're trying to reflect using objects.
In your case, every Question can be assigned to multiple Categories - so that's a sign of #*ToMany relationship. Now you have to decide if:
each Category can have only one Question assigned to it (it will result in a unique constraint which means that no other Category can refer the same Question) - this will be #OneToMany relationship,
each Category can have multiple Questions assigned to it (there will be no unique constraint in the Category table) - this will be #ManyToMany relationship.
#OneToMany (Question -> Category)
This relationship can be represented by join table only if you explicitly define so using #JoinTable or when it is a unidirectional relationship in which the owning side is the 'One' side (it means that in the Question entity you have a collection of Categories, but in the Categories you don't have any reference to the Question).
If you think about it, it seems quite reasonable that the join table is used. There is no other way the DBMS could save a connection between one row in Question table with multiple rows in Categories table.
However, if you would like to model a bidirectional relationship you need to specify that the Category ('Many' side) is the owning side of the relationship. In this case the DBMS can create a join column with foreign key in the Category table because each Category row can be connected with only one Question.
In this way you don't have any join table but simple foreign keys (still, as pointed at the beginning, you can force to create the join table using #JoinTable).
#ManyToMany
This relationship must be represented as a join table. It basically works very similar to the unidirectional #OneToMany relationship, but in this case you may have multiple rows from Question joined with multiple rows from Categories.
#ManyToMany relationships have mutually referential foreign keys on both sides of the relationship. Sometimes, this relationship is mediated by an adjoining table.
#OneToMany relationships have a foreign key on the "one" side and not on the "many" side. In a #OneToMany relationship, one object is the "parent" and one is the "child". The parent controls the existence of the child.
Remember that a #ManyToMany bi-directional relationship need not be symmetric!
In your Questions & Categories case, you should use #ManyToMany relationship. #ManyToMany basically means that "a Question can belong to many Categories at the same time" and "a Category can contain many Questions at the same time". A new table will automatically be created to store the mappings. Your code would look like this:
#Entity
public class Question implements Serializable {
...
#ManyToMany
private List<Category> categories;
...
}
#Entity
public class Category implements Serializable {
...
#ManyToMany
private List<Question> questions;
...
}
If you use #OneToMany relationship for your Questions and Categories (let's say Category on the One side and Questions on the other), this means that "a Question can only belong to one Category" and "a Category can contain many Questions at the same time". No new table is needed to store the mapping. Instead, a new field will automatically be created in the Many side to record the ID of the One side. Your code would look like this:
#Entity
public class Question implements Serializable {
...
#ManyToOne
private Category theCategory;
...
}
#Entity
public class Category implements Serializable {
...
#OneToMany(mappedBy="theCategory")
private List<Question> questions;
...
}
Related
[this is my DB design](https://i.stack.imgur.com/7ckz4.png)
[Users entitie](https://i.stack.imgur.com/8mMfR.png)
[Roles entitie](https://i.stack.imgur.com/ACYNB.png)
[Project entitie](https://i.stack.imgur.com/ZJXKC.png)
The relation between Users and Has doesn't need to be unidirectional
Using this composite key class, we can create the entity class, which models the join table:
#Entity
class CourseRating {
#EmbeddedId
CourseRatingKey id;
#ManyToOne
#MapsId("studentId")
#JoinColumn(name = "student_id")
Student student;
#ManyToOne
#MapsId("courseId")
#JoinColumn(name = "course_id")
Course course;
int rating;
// standard constructors, getters, and setters
}
This code is very similar to a regular entity implementation. However, we have some key differences:
We used #EmbeddedId to mark the primary key, which is an instance of the CourseRatingKey class.
We marked the student and course fields with #MapsId.
#MapsId means that we tie those fields to a part of the key, and they're the foreign keys of a many-to-one relationship. We need it because, as we mentioned, we can't have entities in the composite key.
After this, we can configure the inverse references in the Student and Course entities as before:
class Student {
// ...
#OneToMany(mappedBy = "student")
Set<CourseRating> ratings;
// ...
}
class Course {
// ...
#OneToMany(mappedBy = "course")
Set<CourseRating> ratings;
// ...
}
Note that there's an alternative way to use composite keys: the #IdClass annotation.
3.4. Further Characteristics
We configured the relationships to the Student and Course classes as #ManyToOne. We could do this because with the new entity we structurally decomposed the many-to-many relationship to two many-to-one relationships.
Why were we able to do this? If we inspect the tables closely in the previous case, we can see that it contained two many-to-one relationships. In other words, there isn't any many-to-many relationship in an RDBMS. We call the structures we create with join tables many-to-many relationships because that's what we model.
Besides, it's more clear if we talk about many-to-many relationships because that's our intention. Meanwhile, a join table is just an implementation detail; we don't really care about it.
Moreover, this solution has an additional feature we haven't mentioned yet. The simple many-to-many solution creates a relationship between two entities. Therefore, we cannot expand the relationship to more entities. But we don't have this limit in this solution: we can model relationships between any number of entity types.
For example, when multiple teachers can teach a course, students can rate how a specific teacher teaches a specific course. That way, a rating would be a relationship between three entities: a student, a course and a teacher.
I have two tables: Student and Address. A student has many addresses and I am trying to use #OneToMany on the Student table. A question came into mind what if I use #ManyToOne on the Address table to mention that one Address belongs to Many Students. Please help my clarify my concern.
A single Student has three addresses say Address1, Address2 and Address3.
The Relationship model for above will be, say Student id is a primary key in Student and will act as a foreign key in Address:-
Then in your Address class, you will define this relationship as below:-
#ManyToOne
#JoinColumn(name ="STUDENT_ID")
private Student student;
We use #OneToMany and #ManyToOne, two different annotations, so that we are able to tell Hibernate which object is the child/many part of the relationship and which object is the parent/one side of the relationship.
We are able to tell Hibernate which object is the parent object by assigning the #OneToMany annotation to the appropriate getter method… and which object is the child object by assigning the #ManyToOne annotation to the appropriate getter method.
Hence, Address becomes child side of relationship and Student becomes
parent side of relationship.
You might even use both if it makes sense. Basically you define in which direction the relation is navigable, e.g. if a student has an address you'll probably want to be able to navigate from that student to her address. However, an address might be shared by multiple persons which are not only students so the relation on that side might be different (or not needed at all).
Whatever you decide there's one thing you should keep in mind: you should define one side of the relation to be the owner (owning side) as otherwise you'd confuse Hibernate and get unexpected results. If there's only one side (i.e. Student->Adress but not the other way round) it's easy, if you got both sides you need to declare one the owning side - in most cases this will be the "many"-side, i.e. where you put the #ManyToOne. The other side must be declared as non-owning or you get two owning sides, e.g. by adding mappedBy="name_on_owning_side" to #OneToMany.
Example:
class Student {
#ManyToOne
Address address;
}
class Address {
#OneToMany( mappedBy = "address" )
Set<Student> residents;
}
Here Student is the owner of the bidirectional relation (which allows you to navigate student->address and address->resident(student) ) and only changes to Student.address would be written to the database.
A final note: as you can see that's quite a complex topic so you might want to have a look at some tutorial, e.g. here: https://en.wikibooks.org/wiki/Java_Persistence/ManyToOne and https://en.wikibooks.org/wiki/Java_Persistence/OneToMany
I am working on java application and using JPA to interact with the database, I have two important questions:
I want to make a bi-directional link between two classes since I need to access the data on both sides. Let's take the case of two classes A and B with A *-1 B (as UML diagram, A has an unique B and B has several A ..).
in A:
#ManyToOne
private B attribute;
in B
#OneToMany
private List<A> list;
Is that enough to make the two-way link? or it is mandatory to use the mappedBy?
Which brings us to my second question, if the mappedBy is placed on the wrong side, it'll just impact the performance or even worse ? (data not persisted)? For example in the case of the cardinality 1-* we have no choice, the mappedBy should be in the side of OneToMany and in this case:
in B
#OneToMany(mappedBy = "attribute")
private List<A> list;
Knowing the fact that I will not create the class B, and create a List and assign objects, I will do nothing in the side B. I'll just create repeatedly classes A and every time I assign it an B object, so I may have several classes A that have the same affected object B and I want that B automatically updates this link and its list of A.
Is that enough to make the two-way link? or it is mandatory to use the
mappedBy?
For a Bi-directional relationship it is mandatory .
Which brings us to my second question, if the mappedBy is placed on
the wrong side, it'll just impact the performance or even worse ?
(data not persisted)?
Worse - It will not work but it will not be silent fail you will see exceptions.
Having said that is simple to understand . It goes with #OneToMany .
This might help you understanding this more.
mappedBy should be added to the entity which does not have a foreign key in its table (most likely B in this case).
If mappedBy is on the wrong side, you should see an exception.
Is that enough to make the two-way link? or it is mandatory to use the
mappedBy?
Not quite. You do need the MappedBy attribute for bidirectional many-to-one relationships on the inverse side - that is the side that does not have the foreign key, and is always the one side in a many-to-one relationship. You also need joincolumn information on the many side of the relationship.
So in summary:
Many-to-one side – the owning side of the relationship - #JoinColumn information is on this side.
This needs to be specified in both uni-directional and bidirectional relationships
One-to-many side – the inverse side – mappedBy Attribute on this side.
This needs to be specified if the relationship is bidirectional.
#Entity
public class A ……..
//Owning side of the relationship with the #JoinColumn annotation.
#ManyToOne
// Assume TABLEPK column holds PK of B's table
#JoinColumn (name = "TABLEBPK")
private B attribute;
#Entity
public class B ……
//Inverse side of the relationship with the MappedBy attribute.
#OneToMany(MappedBy = “attribute”)
private List<A> list;
Which brings us to my second question, if the mappedBy is placed on
the wrong side, it'll just impact the performance or even worse ?
It won't work. Just put it on the inverse side of the relationship.
Knowing the fact that I will not create the class B, and create a List
and assign objects, I will do nothing in the side B. I'll just create
repeatedly classes A and every time I assign it an B object, so I may
have several classes A that have the same affected object B and I want
that B automatically updates this link and its list of A.
In this scenario, you create a class A, with the attribute field populated with an instance of B. Now when you persist A - a new instance - it will contain an instance of B in the attribute field that may or may not be new. We want JPA to persiste A and then navigate accross the relationship and persist B also. If B already exists in the perssitence context then ignore it. Adding CascadeType.PERSIST will achieve this.
#Entity
public class A ……..
//Owning side of the relationship with the #JoinColumn annotation.
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn (name = "TABLEBPK")
private B attribute;
These guys write really well on this stuff....
"Pro JPA 2 Mastering the Java™ Persistence API" by Mike Keith and Merrick Schnicariol."
I came across the terms i.e owning side and non-owning side while studying hibernate.For example :- here is
the statement regarding usage of mappedby element in terms of its usage in one to one mapping
If the relationship is bidirectional, the non-owning side must use the
mappedBy element of the OneToOne annotation
to specify the relationship field or property of the owning side.
But i did not get what actually owning side and non-owning side is?
The idea of a owning side of a bidirectional relation comes from the fact that in relational databases there are no bidirectional relations like in the case of objects.
In databases we only have foreign keys, where only one table can have a foreign key to another. Let's take an example that would not work as expected and see why mappedBy is necessary:
#Entity
#Table(name="PERSONS")
public class Person {
#OneToMany
private List<IdDocument> idDocuments;
}
#Entity
#Table(name="IDDOCUMENT")
public class IdDocument {
#ManyToOne
private Person person;
}
This would create not only tables PERSONS and IDDOCUMENTS, but would also create a third table PERSONS_IDDOCUMENTS:
CREATE TABLE persons_iddocument
(
persons_id bigint NOT NULL,
iddocuments_id bigint NOT NULL,
CONSTRAINT fk_persons FOREIGN KEY (persons_id) REFERENCES persons (id),
CONSTRAINT fk_docs FOREIGN KEY (iddocuments_id) REFERENCES iddocument (id),
CONSTRAINT pk UNIQUE (iddocuments_id)
)
Notice the primary key on documents only. In this case Hibernate tracks both sides of the relation independently: If you add a document to relation Person.idDocuments, it inserts a record in PERSON_IDDOCUMENTS.
If we change the Person of a IdDocument, it changes the foreign key person_id on table IDDOCUMENTS.
Hibernate is creating two unidirectional (foreign key) relations on the database, to implement one bidirectional object relation, because databases do not support bidirectional relations.
But what we want is for the object relation to be only mapped by the foreign key on table IDDOCUMENTS towards PERSON: one document belongs to only one person.
There is no need for the extra table, that would force us to modify both Person.idDocuments and IdDocument.person inside the same database transaction to keep the relation consistent.
To solve this we need to configure Hibernate to stop tracking the modifications on relation Person.idDocuments. Hibernate should only track the other side of the relation IdDocument.person, and to do so we add mappedBy:
#OneToMany(mappedBy="person")
private List<IdDocument> idDocuments;
This means "modifications on this side of the relation are already Mapped By by the other side of the relation IdDocument.person, so no need to track it here separately in an extra table".
This gives us the mapping we want, but has one major consequence:
Modifications on the Person.idDocuments collection are no longer tracked by Hibernate, and it is the responsibility of the developer to modify IdDocument.person instead in order to modify the association.
The 'owning' side is the entity whose table will hold the reference.
If you have a one-to-one relationship between EntityPerson and EntityAddress, then, if EntityPerson is the owning side, it will have in its table something like
ADDRESS_ID int NULL FOREIGN KEY REFERENCES Address (ID)
Here is my understanding with simple example where College has many students(One to many relationship)
corresponds to
College(Value Object) -----------------> College (Database Table)
corresponds to
Student(Value Object) -----------------> Student (Database Table having column which is
foreign key to College table .
So This is owning side and College is
Non-owning side )
In terms of Object representation, Student object is owning side becoz it will be having reference pointing to college column.So Student is owning side and College in non-owning side.
Usage of Owner side and Non-Owning side in hibernate in relation of mapped by element
Non-Owning Side Object
#Entity
public class College {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int collegeId;
#OneToMany(mappedBy="college") // here non-owning side using mapped by elment to specify
// the relationship field of owning side
private List<Student> students;
}
Owning Side Object
#Entity
public class Student {
#ManyToOne
private College college;
}
In conclusion the owning side is the entity that has the reference to the other. In terms of DB, it
translate to table entity having column which is foreign key to column in other table like in
case of College has many students.
Note:- owning-side table must contain a join column that refers to the other table's id.It means owning side entity should contain #joincolumn annotation otherwise it will consider the name as primary key column name of other table. See #OneToOne unidirectional and bidirectional
Ok so this is probably a trivial question but I'm having trouble visualizing and understanding the differences and when to use each. I'm also a little unclear as to how concepts like uni-directional and bi-directional mappings affect the one-to-many/many-to-many relationships. I'm using Hibernate right now so any explanation that's ORM related will be helpful.
As an example let's say I have the following set-up:
public class Person {
private Long personId;
private Set<Skill> skills;
//Getters and setters
}
public class Skill {
private Long skillId;
private String skillName;
//Getters and setters
}
So in this case what kind of mapping would I have? Answers to this specific example are definitely appreciated but I would also really like an overview of when to use either one-to-many and many-to-many and when to use a join table versus a join column and unidirectional versus bidirectional.
Looks like everyone is answering One-to-many vs. Many-to-many:
The difference between One-to-many, Many-to-one and Many-to-Many is:
One-to-many vs Many-to-one is a matter of perspective. Unidirectional vs Bidirectional will not affect the mapping but will make difference on how you can access your data.
In Many-to-one the many side will keep reference of the one side. A good example is "A State has Cities". In this case State is the one side and City is the many side. There will be a column state_id in the table cities.
In unidirectional, Person class will have List<Skill> skills but
Skill will not have Person person. In bidirectional, both
properties are added and it allows you to access a Person given a
skill( i.e. skill.person).
In One-to-Many the one side will be our point of reference. For example, "A User has Addresses". In this case we might have three columns address_1_id, address_2_id and address_3_id or a look up table with multi column unique constraint on user_id
on address_id.
In unidirectional, a User will have Address address. Bidirectional
will have an additional List<User> users in the Address class.
In Many-to-Many members of each party can hold reference to arbitrary number of members of the other party. To achieve this a look up table is used. Example for this is the relationship between doctors and patients. A doctor can have many patients and vice versa.
One-to-Many: One Person Has Many Skills, a Skill is not reused between Person(s)
Unidirectional: A Person can directly reference Skills via its Set
Bidirectional: Each "child" Skill has a single pointer back up to the
Person (which is not shown in your code)
Many-to-Many: One Person Has Many Skills, a Skill is reused between Person(s)
Unidirectional: A Person can directly reference Skills via its Set
Bidirectional: A Skill has a Set of Person(s) which relate to it.
In a One-To-Many relationship, one object is the "parent" and one is the "child". The parent controls the existence of the child. In a Many-To-Many, the existence of either type is dependent on something outside the both of them (in the larger application context).
Your subject matter (domain) should dictate whether or not the relationship is One-To-Many or Many-To-Many -- however, I find that making the relationship unidirectional or bidirectional is an engineering decision that trades off memory, processing, performance, etc.
What can be confusing is that a Many-To-Many Bidirectional relationship does not need to be symmetric! That is, a bunch of People could point to a skill, but the skill need not relate back to just those people. Typically it would, but such symmetry is not a requirement. Take love, for example -- it is bi-directional ("I-Love", "Loves-Me"), but often asymmetric ("I love her, but she doesn't love me")!
All of these are well supported by Hibernate and JPA. Just remember that Hibernate or any other ORM doesn't give a hoot about maintaining symmetry when managing bi-directional many-to-many relationships...thats all up to the application.
1) The circles are Entities/POJOs/Beans
2) deg is an abbreviation for degree as in graphs (number of edges)
PK=Primary key, FK=Foreign key
Note the contradiction between the degree and the name of the side. Many corresponds to degree=1 while One corresponds to degree >1.
One-to-many
The one-to-many table relationship looks like this:
In a relational database system, a one-to-many table relationship associates two tables based on a Foreign Key column in the child table referencing the Primary Key of one record in the parent table.
In the table diagram above, the post_id column in the post_comment table has a Foreign Key relationship with the post table id Primary Key column:
ALTER TABLE
post_comment
ADD CONSTRAINT
fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
#ManyToOne annotation
In JPA, the best way to map the one-to-many table relationship is to use the #ManyToOne annotation.
In our case, the PostComment child entity maps the post_id Foreign Key column using the #ManyToOne annotation:
#Entity(name = "PostComment")
#Table(name = "post_comment")
public class PostComment {
#Id
#GeneratedValue
private Long id;
private String review;
#ManyToOne(fetch = FetchType.LAZY)
private Post post;
}
Using the JPA #OneToMany annotation
Just because you have the option of using the #OneToMany annotation, it doesn't mean it should be the default option for all the one-to-many database relationships.
The problem with JPA collections is that we can only use them when their element count is rather low.
The best way to map a #OneToMany association is to rely on the #ManyToOne side to propagate all entity state changes:
#Entity(name = "Post")
#Table(name = "post")
public class Post {
#Id
#GeneratedValue
private Long id;
private String title;
#OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
//Constructors, getters and setters removed for brevity
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
}
The parent Post entity features two utility methods (e.g. addComment and removeComment) which are used to synchronize both sides of the bidirectional association.
You should provide these methods whenever you are working with a bidirectional association as, otherwise, you risk very subtle state propagation issues.
The unidirectional #OneToMany association is to be avoided as it's less efficient than using #ManyToOne or the bidirectional #OneToMany association.
One-to-one
The one-to-one table relationship looks as follows:
In a relational database system, a one-to-one table relationship links two tables based on a Primary Key column in the child which is also a Foreign Key referencing the Primary Key of the parent table row.
Therefore, we can say that the child table shares the Primary Key with the parent table.
In the table diagram above, the id column in the post_details table has also a Foreign Key relationship with the post table id Primary Key column:
ALTER TABLE
post_details
ADD CONSTRAINT
fk_post_details_id
FOREIGN KEY (id) REFERENCES post
Using the JPA #OneToOne with #MapsId annotations
The best way to map a #OneToOne relationship is to use #MapsId. This way, you don't even need a bidirectional association since you can always fetch the PostDetails entity by using the Post entity identifier.
The mapping looks like this:
#Entity(name = "PostDetails")
#Table(name = "post_details")
public class PostDetails {
#Id
private Long id;
#Column(name = "created_on")
private Date createdOn;
#Column(name = "created_by")
private String createdBy;
#OneToOne(fetch = FetchType.LAZY)
#MapsId
#JoinColumn(name = "id")
private Post post;
public PostDetails() {}
public PostDetails(String createdBy) {
createdOn = new Date();
this.createdBy = createdBy;
}
//Getters and setters omitted for brevity
}
This way, the id property serves as both Primary Key and Foreign Key. You'll notice that the #Id column no longer uses a #GeneratedValue annotation since the identifier is populated with the identifier of the post association.
Many-to-many
The many-to-many table relationship looks as follows:
In a relational database system, a many-to-many table relationship links two parent tables via a child table which contains two Foreign Key columns referencing the Primary Key columns of the two parent tables.
In the table diagram above, the post_id column in the post_tag table has also a Foreign Key relationship with the post table id Primary Key column:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post
And, the tag_id column in the post_tag table has a Foreign Key relationship with the tag table id Primary Key column:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag
Using the JPA #ManyToMany mapping
This is how you can map the many-to-many table relationship with JPA and Hibernate:
#Entity(name = "Post")
#Table(name = "post")
public class Post {
#Id
#GeneratedValue
private Long id;
private String title;
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "post_tag",
joinColumns = #JoinColumn(name = "post_id"),
inverseJoinColumns = #JoinColumn(name = "tag_id")
)
private Set<Tag> tags = new HashSet<>();
//Getters and setters ommitted for brevity
public void addTag(Tag tag) {
tags.add(tag);
tag.getPosts().add(this);
}
public void removeTag(Tag tag) {
tags.remove(tag);
tag.getPosts().remove(this);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Post)) return false;
return id != null && id.equals(((Post) o).getId());
}
#Override
public int hashCode() {
return getClass().hashCode();
}
}
#Entity(name = "Tag")
#Table(name = "tag")
public class Tag {
#Id
#GeneratedValue
private Long id;
#NaturalId
private String name;
#ManyToMany(mappedBy = "tags")
private Set<Post> posts = new HashSet<>();
//Getters and setters ommitted for brevity
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tag tag = (Tag) o;
return Objects.equals(name, tag.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
}
The tags association in the Post entity only defines the PERSIST and MERGE cascade types. The REMOVE entity state transition doesn't make any sense for a #ManyToMany JPA association since it could trigger a chain deletion that would ultimately wipe both sides of the association.
The add/remove utility methods are mandatory if you use bidirectional associations so that you can make sure that both sides of the association are in sync.
The Post entity uses the entity identifier for equality since it lacks any unique business key. You can use the entity identifier for equality as long as you make sure that it stays consistent across all entity state transitions.
The Tag entity has a unique business key which is marked with the Hibernate-specific #NaturalId annotation. When that's the case, the unique business key is the best candidate for equality checks.
The mappedBy attribute of the posts association in the Tag entity marks that, in this bidirectional relationship, the Post entity owns the association. This is needed since only one side can own a relationship, and changes are only propagated to the database from this particular side.
The Set is to be preferred, as using a List with #ManyToMany is less efficient.
I would explain that way:
OneToOne - OneToOne relationship
#OneToOne
Person person;
#OneToOne
Nose nose;
OneToMany - ManyToOne relationship
#OneToMany
Shepherd shepherd;
#ManyToOne
List<Sheep> sheeps;
ManyToMany - ManyToMany relationship
#ManyToMany
List<Traveler> travelers;
#ManyToMany
List<Destination> destinations;
Take a look at this article: Mapping Object Relationships
There are two categories of object relationships that you need to be concerned with when mapping. The first category is based on multiplicity and it includes three types:
*One-to-one relationships. This is a relationship where the maximums of each of its multiplicities is one, an example of which is holds relationship between Employee and Position in Figure 11. An employee holds one and only one position and a position may be held by one employee (some positions go unfilled).
*One-to-many relationships. Also known as a many-to-one relationship, this occurs when the maximum of one multiplicity is one and the other is greater than one. An example is the works in relationship between Employee and Division. An employee works in one division and any given division has one or more employees working in it.
*Many-to-many relationships. This is a relationship where the maximum of both multiplicities is greater than one, an example of which is the assigned relationship between Employee and Task. An employee is assigned one or more tasks and each task is assigned to zero or more employees.
The second category is based on
directionality and it contains two
types, uni-directional relationships
and bi-directional relationships.
*Uni-directional relationships. A uni-directional relationship when an object knows about the object(s) it is related to but the other object(s) do not know of the original object. An example of which is the holds relationship between Employee and Position in Figure 11, indicated by the line with an open arrowhead on it. Employee objects know about the position that they hold, but Position objects do not know which employee holds it (there was no requirement to do so). As you will soon see, uni-directional relationships are easier to implement than bi-directional relationships.
*Bi-directional relationships. A bi-directional relationship exists when the objects on both end of the relationship know of each other, an example of which is the works in relationship between Employee and Division. Employee objects know what division they work in and Division objects know what employees work in them.
this would probably call for a many-to-many relation ship as follows
public class Person{
private Long personId;
#manytomany
private Set skills;
//Getters and setters
}
public class Skill{
private Long skillId;
private String skillName;
#manyToMany(MappedBy="skills,targetClass="Person")
private Set persons; // (people would not be a good convenion)
//Getters and setters
}
you may need to define a joinTable + JoinColumn but it will possible work also without...
First of all, read all the fine print. Note that NHibernate (thus, I assume, Hibernate as well) relational mapping has a funny correspondance with DB and object graph mapping. For example, one-to-one relationships are often implemented as a many-to-one relationship.
Second, before we can tell you how you should write your O/R map, we have to see your DB as well. In particular, can a single Skill be possesses by multiple people? If so, you have a many-to-many relationship; otherwise, it's many-to-one.
Third, I prefer not to implement many-to-many relationships directly, but instead model the "join table" in your domain model--i.e., treat it as an entity, like this:
class PersonSkill
{
Person person;
Skill skill;
}
Then do you see what you have? You have two one-to-many relationships. (In this case, Person may have a collection of PersonSkills, but would not have a collection of Skills.) However, some will prefer to use many-to-many relationship (between Person and Skill); this is controversial.
Fourth, if you do have bidirectional relationships (e.g., not only does Person have a collection of Skills, but also, Skill has a collection of Persons), NHibernate does not enforce bidirectionality in your BL for you; it only understands bidirectionality of the relationships for persistence purposes.
Fifth, many-to-one is much easier to use correctly in NHibernate (and I assume Hibernate) than one-to-many (collection mapping).
Good luck!