Проектирование 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 класс будет содержать коллекцию Groups:

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 решает проблемы или даже идет вперед и использует их вместо этого.