Bir-Çok, Çok-Bir ve Çok-Çok arasındaki fark?


144

Tamam, bu muhtemelen önemsiz bir soru ama farklılıkları ve her birini ne zaman kullanacağınızı görselleştirmek ve anlamakta zorlanıyorum. Tek yönlü ve çift yönlü eşlemeler gibi kavramların bir-çok / çok-çok ilişkilerini nasıl etkilediği konusunda biraz belirsizim. Şu anda Hibernate kullanıyorum, bu yüzden ORM ile ilgili herhangi bir açıklama yardımcı olacaktır.

Örnek olarak, aşağıdaki kuruluma sahip olduğumu varsayalım:

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
}

Peki bu durumda ne tür bir haritaya sahip olurdum? Bu özel örneğe verilen cevaplar kesinlikle takdir edilmekle birlikte, ne zaman bir-çok ve çok-çok kullanılacağı ve birleştirme tablosunun birleştirme sütununa ve tek yönlü veya çift yönlü ne zaman kullanılacağı konusunda genel bir bakış istiyorum.


11
Görünüşe göre herkes sadece bire çok veya çoktan çoğa cevap veriyor. Bire çok vs Çoktan bire cevabımın cevabına bak.
Alexander Suraphel

Yanıtlar:


165

Bire Çok : Bir Kişinin Çok Beceri Var, Bir Beceri Kişi (ler) arasında yeniden kullanılmaz

  • Tek Yönlü : Bir Kişi Becerilerini Setinden doğrudan referans alabilir
  • Çift Yönlü : Her "alt" Beceri, Kişiye (kodunuzda gösterilmeyen) kadar geri gelen tek bir işaretçiye sahiptir.

Çoktan Çoğa : Bir Kişinin Çok Beceri Var, Bir Beceri Kişi (ler) arasında yeniden kullanılır

  • Tek Yönlü : Bir Kişi Becerilerini Setinden doğrudan referans alabilir
  • Çift Yönlü : Bir Beceri, kendisiyle ilişkili bir Kişi (ler) e sahiptir.

Bire Çok ilişkisinde, bir nesne "üst" ve diğeri "alt" tır. Ebeveyn çocuğun varlığını kontrol eder. Çoktan Çoğa'da, her iki türün varlığı her ikisinin dışında bir şeye bağlıdır (daha büyük uygulama bağlamında).

Konunuz (alan adı), ilişkinin Bir-Çok veya Çok-Çok olup olmadığını dikte etmelidir - ancak, ilişkiyi tek yönlü veya çift yönlü yapmanın bellek, işleme, performans işlemlerini gerçekleştiren bir mühendislik kararı olduğunu görüyorum. , vb.

Kafa karıştırıcı olabilecek şey, Çoktan Çoğa Çift Yönlü bir ilişkinin simetrik olmasına gerek olmamasıdır! Yani, bir grup insan bir yeteneğe işaret edebilir, ancak becerinin sadece bu insanlarla ilgili olması gerekmez. Tipik olarak olurdu, ancak böyle bir simetri bir gereklilik değildir. Örneğin, sevgiyi ele alın - iki yönlüdür ("I-Love", "Loves-Me"), ama genellikle asimetriktir ("Onu seviyorum, ama beni sevmiyor")!

Bunların hepsi Hibernate ve JPA tarafından desteklenmektedir. Hazırda Beklet veya başka bir ORM'nin çift yönlü çoktan çoğa ilişkilerini yönetirken simetriyi koruma konusunda bir yukalamadığını unutmayın ... hepsi bu kadar.


Açıklığa kavuşturmak için, herhangi bir ilişki BL'nizde veya O / R eşlemenizde tek veya çift yönlü olabilir (birbirinden bağımsız, hatta!).
jyoungdev

4
"AŞK" örneği bunu açıklığa kavuşturdu. ManyToMany benim harita tipim.
Abdullah Khan

1
Süper. Bu onu çok iyi açıklıyor (ve OP örneği bağlamında)
Anupam

1
Soruyu doğru cevaplamıyor. bir çok parçayı kaçırıyorsunuz. bire çok ve bire çok bir algı meselesi olmasına rağmen bu cevap bundan bahsetmez.
Manzur Alahi

249

Herkes gibi görünüyor yanıtlıyor One-to-manyVS. Many-to-many:

Arasındaki fark One-to-many, Many-to-oneve Many-to-Manybir:

One-to-manyvs Many-to-onebir perspektif meselesidir . Unidirectionalvs Bidirectional, eşlemeyi etkilemez, ancak verilerinize nasıl erişebileceğiniz konusunda fark yaratır.

  • Gelen tarafının başvurusunu tutacak tarafı. Buna iyi bir örnek "Devletin Şehirleri Var" dır. Bu durumda bir taraf ve çok taraftır. Tabloda bir sütun olacaktır .Many-to-onemanyoneStateCitystate_idcities

Tek yönlü olarak , Personsınıf sahip olacak List<Skill> skillsama Skillolmayacak Person person. In çift yönlü , her iki özellikler eklenmekte ve bir erişmenizi sağlayan Personbir beceri (yani verilen skill.person).

  • Bir One-to-Manytarafta referans noktamız olacak. Örneğin, "Kullanıcının Adresleri Var". Bu durumda biz üç sütun olabilir address_1_id, address_2_idve address_3_idya bir masanın yukarı göz benzersiz üzerinde kısıtlaması ile user_idve address_id.

Tek yönlü , bir Userolacaktır Address address. Çift yönlü ilave bir olacaktır List<User> usersiçinde Addresssınıfında.

  • Gelen Many-to-Manyher partinin üyelerinin diğer parti üyelerinin keyfi sayısına atıf tutabilir. Bunu başarmak için bir arama tablosu kullanılır. Bunun örneği doktorlar ve hastalar arasındaki ilişkidir. Bir doktor birçok hastaya sahip olabilir ya da tam tersi olabilir.

27
bu kabul edilen cevap olmalı, diğer cevapların çoğu soruyu özlüyor.
arg20

İlk örnek yanlış. Bir Kişiniz ve Kişinin @OneToMany Becerileri varsa, bu tablo preson_skills'in skill_id üzerinde benzersiz bir kısıtlaması olacaktır. Yani bir yetenek sadece bir kişiye eşlenirdi. Ve s.personssadece olduğu gibi ayıklayamazsınızs.person
Иван Николайчук

Aslında One-to-manyaçıkladığınız gibi Many-to-manyilişki ilişkidir çünkü personbirçok kişiye gönderme yapar, skillsancak skillbelirli bir kişiye gönderme yapmaz ve birçoğu personsaynı referansa sahip olabilir skill. Ve Many-to-oneilişkiniz aslında bir çocuğun sadece bir annesi One-to-manyolduğu için her becerinin sadece bir referansa personsahip olması.
mixel

@mixel yorumunuz bana cevabımın çoğunu yeniden yazmamı sağladı. Lütfen tekrar kontrol edin! Teşekkürler
Alexander Suraphel

"Bir" tarafın önemiyle Bire çok ve Çoktan bire ayırt edersiniz. Her iki örnekte de "Kullanıcı" en önemli varlıktır. Yani "Bir" (kullanıcılar ve beceriler, skillssahip person_id) olduğunda, o zaman Bire-çok diyorsunuz, ama o "Çok" taraf (kullanıcılar ve adresler, userssahip address_id) ise, o zamana Bir-çok diyorsunuz. Ancak yapısal olarak her iki durum da aynıdır ve Bir-çok olarak adlandırılır.
mixel

38

1) Daireler Varlıklar / POJO'lar / Fasulye

2) deg, grafiklerde olduğu gibi derece için bir kısaltmadır (kenar sayısı)

PK = Birincil anahtar, FK = Yabancı anahtar

Tarafın adı ve derecesi arasındaki çelişkiye dikkat edin. Birçoğu derece = 1'e karşılık gelirken, Biri derece> 1'e karşılık gelir.

Bire çok çoka bir çizimi


1
Nesne grafiğini her iki yönde tablolara nasıl bağladığını gerçekten seviyorum.
Dmitry Minkovsky

3
Bak nerds, PROGRAMMER'İN EL YAPIMI şöyle görünür: D
Mehraj Malik

Burada ne yaptığını görüyorum.
Nick Gallimore

8

Şu makaleye göz atın: Nesne İlişkilerini Eşleme

Eşleme yaparken ilgilenmeniz gereken iki nesne ilişkisi kategorisi vardır. İlk kategori çokluğa dayanır ve üç tür içerir:

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

İkinci kategori yönlülüğe dayanır ve iki yönlü ilişkiler ve çift yönlü ilişkiler içerir.

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

2
this occurs when the maximum of one multiplicity is one and the other is greater than onelolwut?
serg

3

Bu çok yaygın bir soru, bu yüzden bu cevap blogumda yazdığım bu makaleye dayanıyor .

Bire birçok

Bir-çok tablo ilişkisi aşağıdaki gibi görünür:

Bire birçok

İlişkisel veritabanı sisteminde, bire çok tablo ilişkisi , alt tablodaki üst tablo satırına Foreign Keybaşvuruda bulunan sütunu temel alan iki tabloyu birbirine bağlar Primary Key.

Yukarıdaki tablo diyagramda, post_idsütun post_commenttablo bir sahiptir Foreign Keyilişki posttablosu id Primary Keysütun:

ALTER TABLE
    post_comment
ADD CONSTRAINT
    fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post

@ManyToOne ek açıklaması

Birden çok tablo ilişkisini eşlemenin en iyi yolu @ManyToOneek açıklamayı kullanmaktır .

Bizim durumumuzda, alt varlık, ek açıklamayı kullanarak Yabancı Anahtar sütununu PostCommenteşler :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;

}

JPA @OneToManyek açıklamasını kullanma

@OneToManyEk açıklama kullanma seçeneğiniz olması , bunun her bir-çok veritabanı ilişkisi için varsayılan seçenek olması gerektiği anlamına gelmez . Koleksiyonlarla ilgili sorun, bunları yalnızca alt kayıtların sayısı oldukça sınırlı olduğunda kullanabilmemizdir.

Bir @OneToManyilişkilendirmeyi eşlemenin en iyi yolu, @ManyToOnetüm varlık durumu değişikliklerini yaymak için tarafa güvenmektir :

@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);
    }
}

Ana varlık, Postiki yönlü ilişkinin her iki tarafını senkronize etmek için kullanılan iki faydalı yöntem (örneğin addCommentve removeComment) içerir. Her zaman aksi takdirde riske, siz iki yönlü dernek ile çalışıyorsanız her bu yöntemleri sağlamalıdır çok ince devlet yayılma sorunları .

Tek yönlü @OneToManyilişkiden, kullanımdan @ManyToOneveya çift yönlü @OneToManyilişkiden daha az verimli olduğundan kaçınılmalıdır .

@OneToManyJPA ve Hazırda Bekletme ile ilişkiyi eşleştirmenin en iyi yolu hakkında daha fazla bilgi için bu makaleye göz atın .

Bire bir

Bire bir tablo ilişkisi aşağıdaki gibidir:

Bire bir

İlişkisel veritabanı sisteminde, bire bir tablo ilişkisi , alt tablodaki ana tablo satırına Primary Keyda Foreign Keygönderme yapan bir sütuna dayalı olarak iki tabloyu birbirine bağlar Primary Key.

Bu nedenle, alt tablonun Primary Keyana tabloyla paylaştığını söyleyebiliriz .

Yukarıdaki tablo diyagramda, idsütun post_detailstablo da var Foreign Keyolan ilişkiyi posttablo id Primary Keysütun:

ALTER TABLE
    post_details
ADD CONSTRAINT
    fk_post_details_id
FOREIGN KEY (id) REFERENCES post

JPA kullanarak @OneToOnebirlikte @MapsIdek açıklamalar

Bir @OneToOneilişkiyi eşlemenin en iyi yolu kullanmaktır @MapsId. Bu şekilde, varlık tanımlayıcısını PostDetailskullanarak varlığı her zaman getirebileceğiniz için çift yönlü bir ilişkilendirmeye bile ihtiyacınız yoktur Post.

Eşleme şöyle görünür:

[code language = "java"] @Entity (name = "PostDetails") @Table (name = "post_details") genel sınıf 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

} [/ kod]

Bu şekilde, idtesis hem Ana Anahtar hem de Yabancı Anahtar olarak hizmet vermektedir. Tanımlayıcı ilişkilendirmenin tanımlayıcısıyla doldurulduğundan @Idsütunun artık bir @GeneratedValueek açıklama kullanmadığını fark edeceksiniz post.

@OneToOneJPA ve Hazırda Bekletme ile ilişkiyi eşleştirmenin en iyi yolu hakkında daha fazla bilgi için bu makaleye göz atın .

Birçok çoğa

Çoktan çoğa tablo ilişkisi şöyle görünür:

Birçok çoğa

İlişkisel veritabanı sisteminde, çoktan çoğa tablo ilişkisi , iki üst tabloyu, iki üst tablodaki Foreign Keysütunlara başvuran iki sütun içeren bir alt tablo aracılığıyla bağlar Primary Key.

Yukarıdaki tablo diyagramda, post_idsütun post_tagtablo da var Foreign Keyolan ilişkiyi posttablo id Primary Keysütun:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post

Ve, tag_idsütun post_tagtabloda bir sahip Foreign Keyile ilişki tagtablo id Primary Keysütununun:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag

JPA @ManyToManyeşlemesini kullanma

many-to-manyJPA ve Hazırda Bekletme ile tablo ilişkisini şu şekilde eşleyebilirsiniz :

@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 31;
    }
}

@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. Varlıktaki tagsilişkilendirme Postyalnızca PERSISTve MERGEbasamaklı türleri tanımlar . Bu makalede açıklandığı gibi , REMOVE varlık durumu geçişi , bir @ManyToManyJPA ilişkilendirmesi için hiçbir anlam ifade etmemektedir, çünkü birliğin her iki tarafını da silecek bir zincir silinmesini tetikleyebilir.
  2. Bu makalede açıklandığı gibi , çift yönlü ilişkilendirmeler kullanırsanız, ilişkilendirmenin her iki tarafının da eşit olduğundan emin olmak için ekleme / kaldırma yardımcı programı yöntemleri zorunludur.
  3. PostHerhangi benzersiz iş anahtarını yoksun beri varlık eşitlik için varlık tanımlayıcı kullanır. Bu makalede açıklandığı gibi, tüm varlık durumu geçişlerinde tutarlı kaldığından emin olarak varlık tanımlayıcısını eşitlik için kullanabilirsiniz .
  4. TagVarlık hazırda özgü işaretlenir benzersiz bir iş anahtarı vardır @NaturalIdaçıklama. Böyle bir durumda, benzersiz iş anahtarı eşitlik kontrolleri için en iyi adaydır .
  5. mappedByÖznitelik postsiçinde dernek Tag, bu iki yönlü bir ilişki içinde, varlık işaretleri Postvarlık ilişki var. Bu, yalnızca bir tarafın bir ilişkiye sahip olabileceği ve değişikliklerin veritabanına yalnızca bu belirli taraftan yayıldığı için gereklidir.
  6. SetKullanarak olarak tercih edilir Listolan @ManyToManydaha az verimlidir.

@ManyToManyJPA ve Hazırda Bekletme ile ilişkiyi eşleştirmenin en iyi yolu hakkında daha fazla bilgi için bu makaleye göz atın .


1

bu muhtemelen aşağıdaki gibi çoktan çoğa bir ilişki gemisi gerektirecektir.



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
}

joinTable + JoinColumn tanımlamanız gerekebilir, ancak mümkün olmadan da çalışacaktır ...


1

Ben şöyle açıklıyorum:

OneToOne - OneToOne ilişkisi

@OneToOne
Person person;

@OneToOne
Nose nose;

OneToMany - ManyToOne ilişkisi

@OneToMany
Shepherd> shepherd;

@ManyToOne
List<Sheep> sheeps;

ManyToMany - ManyToMany ilişkisi

@ManyToMany
List<Traveler> travelers;

@ManyToMany
List<Destination> destinations;

0

Her şeyden önce, tüm ince baskıyı okuyun. NHibernate (bu nedenle, Hibernate de var) ilişkisel eşleme DB ve nesne grafik eşleme ile komik bir uyum vardır unutmayın. Örneğin, bire bir ilişkiler genellikle çoktan bire bir ilişki olarak uygulanır.

İkincisi, size O / R haritanızı nasıl yazmanız gerektiğini söylemeden önce, DB'nizi de görmeliyiz. Özellikle, tek bir Beceri birden fazla kişi tarafından ele geçirilebilir mi? Eğer öyleyse, çoktan çoğa bir ilişkiniz var; aksi takdirde, birebir.

Üçüncüsü, doğrudan çoktan çoğa ilişkileri uygulamayı tercih etmiyorum, bunun yerine etki alanı modelinizdeki "birleştirme tablosunu" modelleyin - yani, böyle bir varlık gibi davranın:

class PersonSkill 
{
    Person person;
    Skill skill;    
}

O zaman neye sahip olduğunuzu görüyor musunuz? İki bire çok ilişkiniz var. (Bu durumda, Kişi bir PersonSkills koleksiyonuna sahip olabilir, ancak bir Beceri koleksiyonuna sahip olmaz.) Ancak, bazıları çoktan çoğa ilişkiyi (Kişi ile Beceri arasında) kullanmayı tercih edecektir; bu tartışmalıdır.

Dördüncüsü, sen iki yönlü ilişkiler yaparsanız (örneğin, sadece Kişi Becerileri bir koleksiyona sahip, ama aynı zamanda, Beceri Kişilerin bir koleksiyona sahiptir yapar) NHibernate yok değil sizin için BL İki yönlülük uygulamak; yalnızca kalıcılık amacıyla ilişkilerin çift yönlülüğünü anlar.

Beşinci olarak, NHibernate'de (ve Hazırda Bekletme olduğunu varsayalım) bire çokdan (toplama eşlemesi) çoktan bire doğru kullanımı çok daha kolaydır.

İyi şanslar!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.