Отображать атрибуты отношения многих ко многим, закодированные с помощью @OneToMany и @ManyToOne - PullRequest
1 голос
/ 27 февраля 2012

Я новичок весной.Я думаю, что лучше объяснить мою проблему небольшим примером.Допустим, у меня есть два основных класса: User и Group.User может быть частью более Group с, а Group, очевидно, может иметь больше User с.Так что отношения между ними многие ко многим.Я хотел бы показать, что-то вроде этого (с использованием JSTL):

<c:forEach items="${groups}" var="group">
    <c:out value="${group.name}"/> (<c:out value="${fn:length(group.users)}" />):<br />
    <c:forEach items="${groups.users}" var="user">
        <c:out value="${user.name}"/><br />
    </c:forEach><br />
</c:forEach>

По сути, вывод должен быть примерно таким:

Случайно (2):ДжоBloggsЗвездные войны (5):ЛюкЧубаккаДарт ВейдерПринцесса леяYodaNintendo (3):супер МариоMetroidZelda

Сначала я закодировал его классической аннотацией @ManyToMany, используя дополнительную таблицу user_has_group (созданную и управляемую JPA), и она работала отлично.

Мне нужно былоизмените структуру, так как мне нужно, чтобы в таблице user_has_group был столбец joined_date.Чтобы достичь этого, я прочитал в Интернете, что лучшим решением является создание другого класса (например, UserHasGroup) и добавление отношений «один ко многим» к этому классу из User и group.Таким образом, можно добавить дополнительные атрибуты в класс UserHasGroup (и, следовательно, дополнительные столбцы в таблицу user_has_group).Что-то вроде:

Пользователь:

@Entity
@Table(name = "user")
public class User
{
    @Id
    @GeneratedValue
    @Column
    private int id;

    @Column
    private String alias;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
    private List<UserHasGroup> userHasGroup = new ArrayList<UserHasGroup>();

    // Constructors/getters/setters
}

Группа:

@Entity
@Table(name = "`group`")
public class Group
{
    @Id
    @GeneratedValue
    @Column
    private int id;

    @Column
    private String name;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "group")
    private List<UserHasGroup> userHasGroup = new ArrayList<UserHasGroup>();

    // Constructors/getters/setters
}

UserHasGroup:

@Entity
@Table(name = "user_has_group")
public class UserHasGroup
{
    @Id
    @GeneratedValue
    @Column
    private int id;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne
    @JoinColumn(name = "group_id")
    private Group group;

    @Column
    @Temporal(TemporalType.DATE)
    private Date joinedDate;

    // Constructors/getters/setters
}

Пока все хорошо.Все тесты выполнены успешно, и функциональность сохраняется.

Но я столкнулся с проблемой с JSTL.Фактически, с этой новой структурой, очевидно, невозможно выполнить group.users для итерации по пользователям.

Каков наилучший способ достичь той же функциональности, что и раньше, но с этой новой структурой?

Спасибо.

1 Ответ

1 голос
/ 27 февраля 2012

Я не вижу причины, по которой $ {fn: length (group.userHasGroup)} не должна работать.

Единственная проблема, с которой вы можете столкнуться - это отсутствие активных сессий. Вы можете решить это либо

  • с использованием перехватчика "open session in view" (который кто-то называет анти-паттерном)

  • ручная итерация по списку в вашем методе обслуживания

  • с нетерпением жду получения отношений - я был бы здесь очень осторожен, так как это может привести ко многим запросам к базе данных

Ответ на дополнительный вопрос:

Это должно выглядеть примерно так:

<c:forEach items="${groups}" var="group">
    <c:out value="${group.name}"/> (<c:out value="${fn:length(group.userHasGroup)}" />):<br />
    <c:forEach items="${groups.userHasGroup}" var="userHasGroup">
         <c:out value="${userHasGroup.user.name}"/><br />
  </c:forEach><br />

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...