Хорошо, это, вероятно, тривиальный вопрос, но у меня проблемы с визуализацией и пониманием различий и того, когда их использовать. Мне также немного неясно, как такие концепции, как однонаправленное и двунаправленное сопоставление, влияют на отношения «один-ко-многим / многие-ко-многим». Я использую 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
}
Итак, какое отображение у меня было бы в этом случае? Ответы на этот конкретный пример, безусловно, приветствуются, но мне также очень хотелось бы получить обзор того, когда использовать один-ко-многим и многие-ко-многим, а когда использовать таблицу соединений вместо столбца соединения и однонаправленную или двунаправленную.
источник
Ответы:
Один ко многим : у одного человека много навыков, навык не используется повторно между людьми
Многие-ко-многим : у одного человека много навыков, навык повторно используется между людьми
В отношениях «один ко многим» один объект является «родительским», а другой - «дочерним». Родитель контролирует существование ребенка. В случае "многие-ко-многим" существование любого типа зависит от чего-то вне их обоих (в более широком контексте приложения).
Ваш предмет (домен) должен диктовать, являются ли отношения один-ко-многим или многие-ко-многим - однако я считаю, что создание отношения однонаправленного или двунаправленного - это инженерное решение, которое требует обмена памяти, обработки и производительности. , так далее.
Что может сбивать с толку, так это то, что двунаправленное отношение «многие ко многим» не обязательно должно быть симметричным! То есть группа людей может указать на навык, но навык не обязательно должен относиться только к этим людям. Обычно это так, но такая симметрия не является обязательной. Возьмем, к примеру, любовь - она двунаправленная («Я люблю», «Любит-меня»), но часто асимметрична («Я люблю ее, но она не любит меня»)!
Все это хорошо поддерживается Hibernate и JPA. Просто помните, что Hibernate или любой другой ORM не заботится о поддержании симметрии при управлении двунаправленными отношениями «многие-ко-многим» ... это все зависит от приложения.
источник
Похоже, все отвечают
One-to-many
vsMany-to-many
.:Разница между
One-to-many
,Many-to-one
иMany-to-Many
заключается в следующем:One-to-many
vsMany-to-one
- это вопрос перспективы .Unidirectional
vsBidirectional
не повлияет на сопоставление, но повлияет на то, как вы можете получить доступ к своим данным.Many-to-one
наmany
стороне будет держать ссылку вone
стороне. Хороший пример - «В государстве есть города». В данном случаеState
это одна сторона, а другаяCity
сторона. Вstate_id
таблице будет столбецcities
.One-to-Many
одной стороны будет наша точка отсчета. Например, «У пользователя есть адреса». В этом случае мы могли бы иметь три колонкиaddress_1_id
,address_2_id
иaddress_3_id
или посмотреть таблицу с уникальным ограничением наuser_id
иaddress_id
.Many-to-Many
членах каждой партии может содержаться ссылка на произвольное количество членов другой стороны. Для этого используется справочная таблица . Примером этого являются отношения между врачами и пациентами. У врача может быть много пациентов и наоборот.источник
s.persons
, так как есть толькоs.person
One-to-many
отношения, как вы описываете, являютсяMany-to-many
отношениями, потому чтоperson
имеют ссылку на многие,skills
ноskill
не содержат ссылки на конкретного человека, и многиеpersons
могут иметь ссылку на то же самоеskill
. И вашиMany-to-one
отношения на самом деле связаны сOne-to-many
тем, что каждый навык имеет отношение только к одному,person
поскольку у ребенка только одна мать.Person
естьList<Skill> skills
на самом деле многие-ко-многим , потому что человек может иметь много навыков и навыков может быть во многихList<Skill> skills
списках. Думаю, вы хотели написать «В однонаправленномSkill
классе придетсяPerson person
».List<Skill> skills
существует,Person
автоматически устанавливает отношения,@Many-to-many
потому что в сгенерированной схеме может бытьunique
ограничение на то,person_id
чтобы умение принадлежало одному человеку. Имеет смысл?1) Кружки - это Entities / POJOs / Beans
2) deg - сокращение от степени, как в графах (количество ребер)
PK = первичный ключ, FK = внешний ключ
Обратите внимание на противоречие между степенью и названием стороны. Многие соответствуют степени = 1, а Один - степени> 1.
источник
Взгляните на эту статью: Сопоставление отношений объектов
*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.
*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 occurs when the maximum of one multiplicity is one and the other is greater than one
лолвут?Один ко многим
Отношение таблиц "один ко многим" выглядит так:
В системе реляционной базы данных отношение таблиц «один ко многим» связывает две таблицы на основе
Foreign Key
столбца в дочерней таблице, ссылающегося наPrimary Key
одну запись в родительской таблице.На диаграмме таблицы выше,
post_id
столбец вpost_comment
таблице имеетForeign Key
отношения сpost
идентификатор таблицыPrimary Key
столбца:ALTER TABLE post_comment ADD CONSTRAINT fk_post_comment_post_id FOREIGN KEY (post_id) REFERENCES post
@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; }
Использование
@OneToMany
аннотации JPAТот факт, что у вас есть возможность использовать
@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); } }
Родительский
Post
объект имеет два служебных метода (например,addComment
иremoveComment
), которые используются для синхронизации обеих сторон двунаправленной ассоциации.Эти методы следует предоставлять всякий раз, когда вы работаете с двунаправленной ассоциацией, поскольку в противном случае вы рискуете очень тонкими проблемами распространения состояния .
@OneToMany
Следует избегать однонаправленной ассоциации, поскольку она менее эффективна, чем использование@ManyToOne
или двунаправленная@OneToMany
ассоциация.Один к одному
Связь таблицы один-к-одному выглядит следующим образом:
В системе реляционной базы данных отношение таблицы один к одному связывает две таблицы на основе
Primary Key
столбца в дочернем элементе, который также являетсяForeign Key
ссылкой наPrimary Key
строку родительской таблицы.Следовательно, мы можем сказать, что дочерняя таблица имеет общий
Primary Key
с родительской таблицей.На диаграмме таблицы выше
id
столбец вpost_details
таблице такжеForeign Key
связан со столбцомpost
таблицыid
Primary Key
:ALTER TABLE post_details ADD CONSTRAINT fk_post_details_id FOREIGN KEY (id) REFERENCES post
Использование JPA
@OneToOne
с@MapsId
аннотациямиЛучший способ обозначить
@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 }
Таким образом,
id
свойство служит как первичным, так и внешним ключом. Вы заметите, что@Id
столбец больше не использует@GeneratedValue
аннотацию, поскольку идентификатор заполняется идентификаторомpost
ассоциации.Многие-ко-многим
Отношения таблицы многие-ко-многим выглядят следующим образом:
В системе реляционной базы данных отношение таблиц «многие ко многим» связывает две родительские таблицы через дочернюю таблицу, которая содержит два
Foreign Key
столбца, ссылающихся наPrimary Key
столбцы двух родительских таблиц.На диаграмме таблицы выше
post_id
столбец вpost_tag
таблице такжеForeign Key
связан со столбцомpost
идентификатора таблицыPrimary Key
:ALTER TABLE post_tag ADD CONSTRAINT fk_post_tag_post_id FOREIGN KEY (post_id) REFERENCES post
Причем,
tag_id
столбец вpost_tag
таблице имеетForeign Key
отношения сtag
ID таблицыPrimary Key
столбца:ALTER TABLE post_tag ADD CONSTRAINT fk_post_tag_tag_id FOREIGN KEY (tag_id) REFERENCES tag
Использование
@ManyToMany
сопоставления JPAВот как вы можете сопоставить
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 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); } }
tags
Объединение вPost
сущности только определяетPERSIST
иMERGE
каскадные типов. Как объясняется в этой статье , изменениеREMOVE
состояния объекта не имеет смысла для@ManyToMany
ассоциации JPA, поскольку он может вызвать удаление цепочки, которое в конечном итоге приведет к стиранию обеих сторон ассоциации.Post
Объект использует идентификатор сущности для равенства , поскольку в нем отсутствует какой - либо уникальный бизнес - ключ. Как объясняется в этой статье , вы можете использовать идентификатор объекта для равенства, если убедитесь, что он остается согласованным при всех переходах состояния объекта .Tag
Объект имеет уникальный бизнес - ключ , который отмечается с Hibernate-специфической@NaturalId
аннотацией. В этом случае уникальный бизнес-ключ является лучшим кандидатом для проверки равенства .mappedBy
Атрибутposts
ассоциации вTag
отметках сущностей , что в этом двунаправленной связи, тоPost
предприятие имеет ассоциацию. Это необходимо, поскольку только одна сторона может владеть отношением, и изменения распространяются в базу данных только с этой конкретной стороны.Set
Является предпочтительным, как использованиеList
с@ManyToMany
менее эффективным.источник
это, вероятно, потребовало бы отношения "многие ко многим" следующим образом
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, но он будет работать и без ...
источник
Я бы так объяснил:
OneToOne - отношения OneToOne
@OneToOne Person person; @OneToOne Nose nose;
OneToMany - отношения ManyToOne
@OneToMany Shepherd> shepherd; @ManyToOne List<Sheep> sheeps;
ManyToMany - отношения ManyToMany
@ManyToMany List<Traveler> travelers; @ManyToMany List<Destination> destinations;
источник
Прежде всего, прочтите все мелким шрифтом. Обратите внимание, что реляционное сопоставление NHibernate (таким образом, я предполагаю, также и Hibernate) имеет забавное соответствие с отображением DB и графа объектов. Например, отношения «один к одному» часто реализуются как отношения «многие к одному».
Во-вторых, прежде чем мы сможем рассказать вам, как вы должны написать свою карту O / R, мы также должны увидеть вашу БД. В частности, могут ли несколько человек владеть одним Навыком? Если это так, то у вас отношения «многие ко многим»; в противном случае - многие к одному.
В-третьих, я предпочитаю не реализовывать отношения «многие ко многим» напрямую, а вместо этого смоделировать «таблицу соединений» в вашей модели предметной области, то есть рассматривать ее как объект, например:
class PersonSkill { Person person; Skill skill; }
Тогда вы видите, что у вас есть? У вас есть два отношения "один ко многим". (В этом случае Person может иметь набор PersonSkills, но не иметь набора навыков.) Однако некоторые предпочтут использовать отношение «многие ко многим» (между Person и Skill); это спорно.
В-четвертых, если у вас действительно есть двунаправленные отношения (например, у человека есть не только набор навыков, но и у навыка есть набор людей), NHibernate не применять двунаправленность в вашем BL для вас; он понимает двунаправленность отношений только для целей сохранения.
В-пятых, в NHibernate гораздо проще правильно использовать «многие-к-одному» (и я предполагаю, что Hibernate), чем «один-ко-многим» (отображение коллекций).
Удачи!
источник