EclipseLink: возможно ли добавить отношение @OneToMany к классу в свойстве @EmbeddedId в качестве внешнего ключа? - PullRequest
1 голос
/ 28 июня 2011

Я хочу создать модуль входа в систему Jaas, используя JPA для хранения моих AuthUser и AuthUserRole .Я сконцентрируюсь на JPA на этом вопросе.

Вот что я бы сделал в базе данных (совсем не законный код SQL, но, надеюсь, всеобъемлющий):

TABLE AuthUser( INT uid, VARCHAR password )
PRIMARY KEY (uid)

TABLE AuthUserRole( INT uid, INT role )
PRIMARY KEY (uid , role)
FOREIGN KEY (uid) REFERENCE AuthUser.uid

Это делаетсмысл для меня, одна роль может быть назначена пользователю только один раз.

Вот что я пытался сделать в Java, не показывая имя пользователя и адрес электронной почты в AuthUser:

@Entity
public class AuthUser {
    @Id
    private int uid;

    private String password;

    @OneToMany
    private Set<AuthUserRole> roles;
}

@Entity
public class AuthUserRole {

    @Embeddedid
    private AuthUserRolePK authUserRolePK;
}

@Embeddable
public class AuthUserRolePK {
    public int uid;
    public int role;
}

Eclipselink делаетсопоставление просто отлично, что означает, что оно работает, но не так, как я хотел.Он создает третью таблицу с именем * authuser_authuserrole *, которая содержит столбцы (AuthUser_uid, uid, role).Нет необходимости упоминать AuthUser_uid и uid идентичны.

Тривиальный ответ будет:

@Entity
public class AuthUser {
    @Id
    private int uid;

    private String password;

    @OneToMany
    @JoinColumn(name="authUserRolePK.uid", referencedColumnName="uid")
    private Set<AuthUserRole> roles;
}

Но EclipseLink кричит, что при использовании @Embeddedid должны быть упомянуты все столбцы первичного ключа.

Q: Как заставить Eclipselink сопоставлять мои объекты, как схема базы данных, которую я упомянул?Стоит ли использовать @IdClass?Я мог видеть результат базы данных -> сопоставление сущностей, но это слишком просто:)

Спасибо за ваши ответы!

1 Ответ

0 голосов
/ 28 июня 2011

Три таблицы - типичный способ сделать это на самом деле, вашему подходу просто не хватает изящества JPA.

Обычно у вас есть три таблицы, связанные следующим образом:

AuthUser        AuthUser_Role (association)       Role
frank     ----         frank,admin       -----    admin

На самом деле это то, что Eclipselink пытался отобразить для вас, но в целом вы не создаете отображение AuthUser_Role самостоятельно.Вместо этого вы создаете поле в AuthUser, например:

@ManyToMany
Set<Roles> userRoles

и (опционально) в роли, например:

@ManyToMany(mappedBy="userRoles")
Set<AuthUser> usersWithRole;

Тогда EclipseLink позаботится о таблице соединений для вас и всех васнужно беспокоиться о поле userRoles, которое будет обновлять объединение.

Вы можете расширить это, чтобы создать объединение вручную, например, для ролей, которые начинаются и заканчиваются в определенный день и т. д., но для всех, кроме большинствасложные проекты, которые обычно не нужны, и часто могут быть выполнены по-другому.В целях обеспечения соответствия проще использовать, например, одно из расширений ELUG для хранения и доступа к истории изменений, что является наиболее распространенной причиной, с которой я столкнулся при добавлении дополнительных метаданных к информации о соединении.


В качестве альтернативы, если вы ДЕЙСТВИТЕЛЬНО хотите сделать это только с двумя таблицами, сделайте AuthUserRole первичной стороной, а AuthUser - пассивной.

@Entity
public class AuthUser {
    @Id
    private int uid;

    private String password;

    @OneToMany(mappedBy="user")
    private Set<AuthUserRole> roles;
}

@Entity
public class AuthUserRole {

    @Embeddedid
    private AuthUserRolePK authUserRolePK;
}

@Embeddable
public class AuthUserRolePK {
    public AuthUser user;
    public int role;
}

В этом случае вы получитетолько две таблицы, и поле «user» действительно будет равно uid AuthUser в базе данных, оно просто отображается как объект на стороне Java.

...