Проектирование DTOs, имеющих отношения внешнего ключа
Я использую Java + Spring framework для веб-приложения. Я не использую инструмент ORM. Вместо этого я пытаюсь моделировать отношения БД как объекты Java, используя простой шаблон DAO/DTO. Всякий раз, когда DTO точно соответствует одной таблице в базе данных, это очень прямолинейно. Но если есть таблицы, которые ссылаются на другие таблицы через внешние ключи, я не уверен, что это лучший подход для этого. Посмотрел в Stackoverflow для подобных ответов, но не смог найти один для моих нужд. Я хотите привести очень конкретный пример-Предположим, есть два объекта User и Group. У меня есть пользователь DTO и группа DTO, каждый из которых имеет UserDao(JdbcUserDao) и GroupDao(JdbcGroupDao) соответственно.
Теперь у меня есть отношение в БД, которое соединяет пользователя и группу. Один пользователь может принадлежать к нескольким группам. Имя таблицы User_Group_Association имеет следующее определение БД:
ид_пользователя | и group_id
здесь user_id-это внешний ключ, ссылающийся на пользователя таблица. Аналогично group_id относится к таблице групп. Когда я моделирую этот DTO в Java, должен ли я сделать что-то вроде этого:
public class UserGroupAssoc {
private int userId;
private int groupId;
//Setters and getters follow
}
или такой:
public class UserGroupAssoc {
private User user;
private Group group;
//Setters and getters follow
}
конкретный случай использования пользовательского интерфейса: я хочу отобразить имена пользователей и соответствующие имена групп, к которым они принадлежат. Что-то вроде этого...--4-->
Имя - > Имена Групп
Keshav - > Admin, EndUser, ReportAdmin
Киран - > ReportAdmin
Pranav - > Конечный Пользователь
В первый подход к дизайну DTO, мне нужно будет снова получить сведения о пользователе (имена) и сведения о группе (имена) из БД. Во втором подходе мне нужно будет получить объекты User и Group при создании самого объекта UserGroupAssoc.
вероятно, в третьем подходе я могу спроектировать UserGroupAssoc DTO следующим образом:
public class UserGroupAssoc {
private String userName;
private String groupName;
private int userId;
private int groupId;
//Setters and getters follow
}
в этом третьем подходе я объединяю таблицы в SQL, чтобы получить только необходимые поля для прецедента, а затем моделирую DTO соответственно.
какой стандартный подход для достижения этого сценария? Соединение таблиц в порядке в дизайне DTO? Некоторые считают, что один DTO должен соответствовать только одной таблице, а связанные объекты должны агрегироваться в слое приложения. Это накладные расходы на выполнение нескольких объектов из БД правильно? Слишком запутался в правильном подходе, извините за такое длинное объяснение!
1 ответов
отказ от ответственности: я не специалист ORM...
... но в классическом многие-ко-многим отношений вам не нужна третья модель данных (UserGroupAssoc
). The User
класс будет содержать коллекцию Group
s:
public class User {
// ... user fields ...
List<Group> groups;
// ... getters/setters ...
}
Если вам нужно также обратное отношение (группа содержит пользователей)Group
класс будет выглядеть так:
public class Group {
// ... group fields ...
List<User> users;
// ... getters/setters ...
}
и опять же, классический способ сделать это-использовать "объекты домена" (ваши DTOs) в коллекции (User
и Group
вместо userId
и groupId
).
вы обычно нужен третий объект домена, только если таблица ассоциации (User_Group_Association
) содержит что-то другое, чем user_id
и group_id
(возможно, какой-то код авторизации, который позволил пользователю быть добавленным в группу, что угодно):
user_id | group_id | auth_code
в этом случае UserGroupAssoc
класс может иметь следующую структуру:
public class UserGroupAssoc {
private User user;
private Group group;
private String authorizationCode;
// ... setters/getters ...
}
и отношение "многие ко многим" между User
и Group
превратит в два отношения "многие к одному" с этим новым объектом домена. Обычно объекты домена предпочтительнее использовать (User
и Group
вместо userId
и groupId
).
какой стандартный подход для достижения этого сценария?
Ну, если бы вы использовали фреймворк ORM, это был бы стандартный способ, которым фреймворк это делал. Но!--43-->поскольку у вас есть пользовательское решение ORM, трудно сказать.
присоединение таблиц в порядке в дизайне DTO?
почему дизайн DTO на уровне приложения должен зависеть от объединения таблиц в базе данных? Это случай для несоответствие объектно-реляционного импеданса и, возможно, также закон дырявых абстракций поскольку вы не можете полностью абстрагировать реляционный домен в объектный домен, сохраняя соответствие 1:1.
некоторые имеют мнения, что один DTO должен соответствует только одной таблице, и связанные объекты должны быть агрегированы в слое приложения. Это накладные расходы на выполнение нескольких объектов из БД правильно?
ORM имеет некоторые ограничения (см. Снова несоответствие объектно-реляционного импеданса для некоторых проблем, с которыми вы можете столкнуться), и трудно моделировать объекты домена для удовлетворения ограничений реляционной базы данных или наоборот. Хорошим примером в этом направлении являются доклады.
отчет обычно агрегирует данные из нескольких таблиц. Это, конечно, не проблема для некоторых SQL-соединений, но как вы собираетесь сопоставить результат с DTOs? Как вы сами сказали...
всякий раз, когда DTO точно соответствует одной таблице в базе данных, это очень прямо вперед
... но результат отчета не будет сопоставляться с одной таблицей, он должен будет сопоставляться с фрагментами из других таблиц.
в зависимости от ваших потребностей в применение, вы можете в конечном итоге с некоторыми странно выглядящими классами или с неловко выглядящими SQLs. Вы можете запустить больше запросов, чем необходимо для получения соответствующих объектных моделей и связей между ними; или у вас может быть больше похожих DTOs, чтобы ограничить количество поездок в базу данных и повысить производительность.
так что я пытаюсь сказать (опять же отказ от ответственности, что я не специалист ORM), что не все приложения являются хорошим кандидатом на ORM; но если вы подумайте об этом, возможно, посмотрите, как Hibernate/JPA решает проблемы или даже идет вперед и использует их вместо этого.