Difference Between One-to-Many, Many-to-One and Many-to-Many?
Asked Answered
B

8

223

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.

Better answered 24/6, 2010 at 21:8 Comment(0)
P
222

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.

Pistil answered 24/6, 2010 at 21:17 Comment(4)
To clarify, any relationship may be uni- or bi-directional in your BL or in your O/R mapping (independently of each other, even!).Subotica
The "LOVE" example just clarified it. ManyToMany is my type of mapping.Jube
Super. This explains it so well (and in the context of OP's example)Drummer
Doesn't answer the question properly. you miss the many to one part. although one to many and many to one is a matter of perception this answer doesn't mention that.Disfrock
E
404

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.
Electrokinetic answered 12/11, 2013 at 8:49 Comment(15)
this should be the accepted answer, most of the other answers miss the question.Mews
First example is incorrect. If you have A Person and Person has @OneToMany with Skills, that table preson_skills would have a unique constraint on skill_id. So one skill would be mapped only to one person. And you can't extract s.persons, as there is only s.personDepside
Actually One-to-many relationship as you describe is Many-to-many relationship because person has a reference to many skills but skill does not keep reference to particular person and many persons can have a reference the same skill. And your Many-to-one relationship is actually One-to-many because each skill has a reference only to one person as a child has only one mother.Wiring
@Wiring your comment ended up making me rewrite most of my answer. Please check it out again! ThanksElectrokinetic
You distinguish between One-to-many and Many-to-one by significance of "One" side. In both examples "User" is most significant entity. So when it's on the "One" (users and skills, skills has person_id) then you call it One-to-many but when it's one the "Many" side (users and addresses, users has address_id) then you call it Many-to-one. But structurally both cases are identical and called One-to-many.Wiring
Also unidirectional One-to-many example when Person have List<Skill> skills is actually Many-to-many because person can have many skills and skill can be in many List<Skill> skills lists. I think you wanted to write "In unidirectional Skill class will have Person person".Wiring
@Wiring I get your point now but I don't think the fact that List<Skill> skills exists in Person makes the relationship automatically @Many-to-many because on the schema generated there could be a unique constraint on person_id making a skill to be owned by one person. Makes sense?Electrokinetic
Yes, but you did not mention that in the answer and still in Java it will be Many-to-many though in generated SQL schema it will have unique constraint which can lead to runtime errors. When discussing particular case we should bring to attention several aspects - structure, semantics and implementations (by different levels of application). So in both examples structurally they are One-to-many. Semantically they are One-to-many and Many-to-one.Wiring
Your answer is different from others because your noticed semantic difference but when talking about relationships they are usually discussed in structure aspect. Implementation at all applications levels also have to be One-to-many but some developers can implement it as One-to-many in database and Many-to-many in Java (as you suggest) which can lead to runtime errors as I said above.Wiring
Very confusing examples! Examples in other answers are better. In short, ManyToOne == OneToMany theoretically, but since this relation means that there is a foreign key on the many sides, in ORM it is easier to define it as ManyToOne (unidirectional). To make is OneToMany, that means the one needs to hold the many so it must be bidirectional (defined on both sides)Cyanogen
@Cyanogen I'd appreciate if you suggest better examples... we're all here to learn, after all!Electrokinetic
@AlexanderSuraphel Vlad Mihalcea's example of posts & comments is classic for one-to-many relations. 1 post has many comments. To implement this, SQL uses a foreign key in comments that points to the post it belongs to, this is a many-to-one relation. But often you need to load post x with its comments, so ORM has this virtual one-to-many relation to make it easier (it is just the reversed direction). For many-to-many example take students & classes, every student has many classes while every class has many students, in SQL you'll have an extra student-class table to make this relationCyanogen
State has many cities is one to many, not many to oneAlgerian
Why does kleppmann(DDIA book author) mention that One-to-Many is easily supported in document databases but not Many-to-one? If it is just a matter of perspective then support for one would imply support for the other.Antetype
@Antetype Good catch. I think it is because document database naturally takes the perspective from the "one" side. For example, a document describing a person may say he/she has many hats. But if you switch to the point of reference where documents describe hats, it's hard to express some hats belong to the same person. However, this issue is not really applicable to RDBMS, where cross-reference tables are frequently used.Orate
P
222

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.

Pistil answered 24/6, 2010 at 21:17 Comment(4)
To clarify, any relationship may be uni- or bi-directional in your BL or in your O/R mapping (independently of each other, even!).Subotica
The "LOVE" example just clarified it. ManyToMany is my type of mapping.Jube
Super. This explains it so well (and in the context of OP's example)Drummer
Doesn't answer the question properly. you miss the many to one part. although one to many and many to one is a matter of perception this answer doesn't mention that.Disfrock
A
49

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.

Illustration of one-to-many many-to-one

Actin answered 2/6, 2013 at 22:11 Comment(2)
Really love how it ties the object graph to the tables in both directions.Tace
Look nerds, this is how PROGRAMMER's HANDWRITING looks like :DFanatic
C
44

One-to-many

The one-to-many table relationship looks like this:

One-to-many

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:

One-to-one

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:

Many-to-many

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);
        }
    }
  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. The Set is to be preferred, as using a List with @ManyToMany is less efficient.
Cailean answered 16/5, 2020 at 13:40 Comment(0)
I
14

I would explain that way:

OneToOne - OneToOne (One Person has one Nose - One Nose has one Peson)

@OneToOne
Person person;

@OneToOne
Nose nose;

OneToMany - ManyToOne (One Shepherd has many sheeps - One sheep has one Shepherd)

@OneToMany
Shepherd shepherd;

@ManyToOne
List<Sheep> sheeps;

ManyToMany - ManyToMany (Many travelers have many destinations -
Many destinations have many travelers)

@ManyToMany
List<Traveler> travelers;

@ManyToMany
List<Destination> destinations;
Ingenious answered 6/10, 2019 at 16:52 Comment(1)
You explained in simple 3 examples. I don't know why people not upvoting for this!Satan
B
9

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. 
Bellyache answered 24/6, 2010 at 21:14 Comment(1)
this occurs when the maximum of one multiplicity is one and the other is greater than one lolwut?Pavlish
D
1

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...

Denman answered 24/6, 2010 at 21:15 Comment(0)
S
0

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!

Subotica answered 24/6, 2010 at 21:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.