一对多,多对一和多对多的区别?

Ian*_*las 129 orm many-to-many hibernate one-to-many

好的,这可能是一个微不足道的问题,但我无法想象和理解差异以及何时使用每个差异.关于单向和双向映射等概念如何影响一对多/多对多关系,我也有点不清楚.我现在正在使用Hibernate,所以任何与ORM相关的解释都会有所帮助.

举个例子,假设我有以下设置:

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
}
Run Code Online (Sandbox Code Playgroud)

那么在这种情况下我会有什么样的映射?这个具体示例的答案肯定是值得赞赏的,但我也非常希望概述何时使用一对多和多对多以及何时使用连接表与连接列以及单向与双向.

Ale*_*hel 214

貌似每个人都回答One-to-manyVS Many-to-many:

之间的区别One-to-many,Many-to-oneMany-to-Many为:

One-to-manyvs Many-to-one是一个透视问题.Unidirectionalvs Bidirectional不会影响映射,但会对您访问数据的方式产生影响.

  • Many-to-onemany侧将保持基准one侧.一个很好的例子是"一个人有很多技能".在这种情况下Stage是一方而且City是多方面.state_id表格中会有一列cities.

单向 Person类中将有List<Skill> skillsSkill不会有Person person.在双向中,两个属性都被添加,它允许您访问Person给定的技能(即skill.person).

  • One-to-Many很多方面将是我们的参考点.例如,"用户有地址".在我们的系统中,许多用户可能共享一个地址(例如,许多人可能共享相同的块号).在这种情况下,表中的address_1_idaddress_2_id将由多个address_3_id行共享.在这种情况下,我们说user_id并且address_idUser关系.

单向一个Address address将有List<User> users.双向AddressMany-to-Many课堂上增加一个.

  • One-to-many每一方的成员可以参考另一方的任意数量的成员.为此,使用查找表.这方面的例子是医生和患者之间的关系.医生可以有很多患者,反之亦然.

  • 这应该是公认的答案,大多数其他答案都错过了这个问题. (20认同)
  • 至少有人...... :) (14认同)
  • 同样单向一​​对多的例子,当`Person`有`List&lt;Skill&gt;技能`时实际上是多对多的,因为一个人可以有很多技能,而技能可以在很多`List&lt;Skill&gt;技能`列表中。我想你想写“在单向的‘技能’类中会有‘人’”。 (2认同)

HDa*_*ave 154

一对多:一个人有很多技能,一个技能不会在人与人之间重复使用

  • 单向:一个人可以通过它的Set直接引用技能
  • 双向:每个"子"技能都有一个指针备份到Person(未在代码中显示)

多对多:一个人有很多技能,一个技能在人之间重复使用

  • 单向:一个人可以通过它的Set直接引用技能
  • 双向:技能具有一组与之相关的人员.

在一对多关系中,一个对象是"父",一个是"子".父母控制孩子的存在.在多对多中,任何一种类型的存在都依赖于它们之外的某些东西(在较大的应用程序上下文中).

你的主题(领域)应该决定关系是一对多还是多对多 - 然而,我发现使关系单向或双向是一种工程决策,可以消除内存,处理,性能等

令人困惑的是,多对多双向关系不需要是对称的!也就是说,一群人可以指出一项技能,但技能不需要仅涉及那些人.通常它会,但这种对称性不是必需的.以爱为例 - 它是双向的("我爱","爱我"),但通常是不对称的("我爱她,但她不爱我")!

所有这些都得到Hibernate和JPA的很好支持.请记住,在管理双向多对多关系时,Hibernate或任何其他ORM都没有提供关于保持对称性的声音......这完全取决于应用程序.

  • "爱"的例子刚刚澄清了它.ManyToMany是我的映射类型. (3认同)

jhe*_*dus 35

1)圆圈是实体/ POJOs /豆

2)deg是度数的缩写,如图(边数)

PK =主键,FK =外键

注意程度和名称之间的矛盾.许多对应于degree = 1而One对应于degree> 1.

一对多多对一的插图

  • 看书呆子,这是**PROGRAMMER****HANDWRITING**的样子:D (2认同)

Vla*_*cea 25

一对多

一对多表关系如下所示:

一对多

在关系数据库系统中,一对多表关系基于Foreign Key子表中的一列引用Primary Key父表中的一条记录来关联两个表。

上表post_id中,post_comment表中的列Foreign Keypost表idPrimary Key列有关系:

    ALTER TABLE
        post_comment
    ADD CONSTRAINT
        fk_post_comment_post_id
    FOREIGN KEY (post_id) REFERENCES post
Run Code Online (Sandbox Code Playgroud)

@ManyToOne 注释

在 JPA 中,映射一对多表关系的最佳方式是使用@ManyToOne注解。

在我们的例子中,PostComment子实体post_id使用@ManyToOne注释映射外键列:

    @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;
        
    }
Run Code Online (Sandbox Code Playgroud)

使用 JPA@OneToMany注释

仅仅因为您可以选择使用@OneToMany注释,并不意味着它应该是所有一对多数据库关系的默认选项。

JPA 集合的问题是我们只能在它们的元素数量相当低时使用它们。

映射@OneToMany关联的最佳方法是依靠@ManyToOne侧来传播所有实体状态更改:

    @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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

Post实体具有两个实用方法(例如addCommentremoveComment),用于同步双向关联的双方。

每当您使用双向关联时,您都应该提供这些方法,否则,您可能会面临非常微妙的状态传播问题

@OneToMany应避免单向关联,因为它比使用@ManyToOne或双向@OneToMany关联效率低。

一对一

一对一的表关系如下所示:

一对一

在关系数据库系统中,一对一的表关系基于Primary Key子表中的列链接两个表,该列也是父表行的Foreign Key引用Primary Key

因此,我们可以说子表Primary Key与父表共享。

在上面的表格图id中,post_details表格中的列也Foreign Keypost表格id Primary Key列有关系:

    ALTER TABLE
        post_details
    ADD CONSTRAINT
        fk_post_details_id
    FOREIGN KEY (id) REFERENCES post
Run Code Online (Sandbox Code Playgroud)

使用@OneToOne带有@MapsId注释的 JPA

映射@OneToOne关系的最佳方法是使用@MapsId. 这样,您甚至不需要双向关联,因为您始终可以PostDetails使用Post实体标识符获取实体。

映射如下所示:

@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
}
Run Code Online (Sandbox Code Playgroud)

这样,该id属性既用作主键又用作外键。您会注意到该@Id列不再使用@GeneratedValue注释,因为标识符填充了post关联的标识符。

多对多

多对多表关系如下所示:

多对多

在关系数据库系统中,多对多表关系通过子表链接两个父表,子表包含Foreign Key引用Primary Key两个父表的列的两列。

在上面的表图post_id中,post_tag表中的列也Foreign Keypost表idPrimary Key列有关系:

    ALTER TABLE
        post_tag
    ADD CONSTRAINT
        fk_post_tag_post_id
    FOREIGN KEY (post_id) REFERENCES post
Run Code Online (Sandbox Code Playgroud)

而且,tag_id在列post_tag表中有一个Foreign Key与关系tag表IDPrimary Key列:

    ALTER TABLE
        post_tag
    ADD CONSTRAINT
        fk_post_tag_tag_id
    FOREIGN KEY (tag_id) REFERENCES tag
Run Code Online (Sandbox Code Playgroud)

使用 JPA@ManyToMany映射

这是您如何many-to-many使用 JPA 和 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);
        }
    }
Run Code Online (Sandbox Code Playgroud)
  1. 实体中的tags关联Post只定义了PERSISTMERGE级联类型。在REMOVE实体状态转换不会使一个任何意义@ManyToManyJPA的关联,因为它可能引发连锁的缺失,最终将擦拭协会的两侧。
  2. 如果您使用双向关联,则添加/删除实用程序方法是必需的,以便您可以确保关联的双方同步。
  3. Post实体使用的相等实体标识符,因为它没有任何独特的业务重点。只要确保它在所有实体状态转换中保持一致,就可以使用实体标识符来表示相等性。
  4. Tag实体具有唯一的业务键,该键标有 Hibernate 特定的@NaturalId注释。在这种情况下,唯一的业务键是平等检查的最佳候选者
  5. 实体中关联的mappedBy属性标志着,在这种双向关系中,实体拥有该关联。这是必需的,因为只有一方可以拥有关系,并且更改仅从这一特定方传播到数据库。postsTagPost
  6. Set是优选的,如使用List具有@ManyToMany效率较低。


Dur*_*aco 14

我会这样解释:

OneToOne - OneToOne (一个人有一个鼻子 - 一个鼻子有一个人)

@OneToOne
Person person;

@OneToOne
Nose nose;
Run Code Online (Sandbox Code Playgroud)

OneToMany - ManyToOne (一个牧羊人有很多羊 - 一只羊有一个牧羊人)

@OneToMany
Shepherd shepherd;

@ManyToOne
List<Sheep> sheeps;
Run Code Online (Sandbox Code Playgroud)

ManyToMany - ManyToMany (许多旅行者有很多目的地 -
许多目的地有很多旅行者)

@ManyToMany
List<Traveler> travelers;

@ManyToMany
List<Destination> destinations;
Run Code Online (Sandbox Code Playgroud)


ale*_*bog 7

看看这篇文章:映射对象关系

映射时需要关注两类对象关系.第一类基于多重性,它包括三种类型:

*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. 
Run Code Online (Sandbox Code Playgroud)

第二类基于方向性,它包含两种类型,单向关系和双向关系.

*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. 
Run Code Online (Sandbox Code Playgroud)

  • `当一个多重性的最大值为1而另一个大于1时,会发生这种情况? (2认同)