Подтвердить что ты не робот

Как создать составной первичный ключ (аннотация java persistence)

Как сделать так, чтобы таблица user_roles определяла два столбца (userID, roleID) как составной первичный ключ. должно быть легко, просто не можете запомнить/найти.

В user entity:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles")
public List<RoleDAO> getRoles() {
    return roles;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getUserID() {
    return userID;
}

В roles entity:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles")
public List<UserDAO> getUsers() {
    return users;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getRoleID() {
    return roleID;
}

Спасибо.

** ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

Итак, существует третья таблица user_roles (автоматически сгенерированная выше), которая принимает userID из user объекта и roleID из roles объекта. Теперь мне нужны эти два столбца в сгенерированной таблице (user_roles) как составной первичный ключ.

4b9b3361

Ответ 1

У вас уже было несколько хороших ответов здесь, как делать то, что вы просите.

Для справки позвольте мне просто упомянуть рекомендуемый способ сделать это в Hibernate вместо этого, который должен использовать суррогатный ключ в качестве первичного ключа и отметить бизнес-ключи как NaturalId's:

Хотя мы рекомендуем использовать суррогатные ключи как первичные ключи, вы следует попытаться определить естественные ключи для всех субъектов. Естественным ключом является свойство или комбинация свойств который является уникальным и непустым. это также непреложный. Сопоставьте свойства естественный ключ внутри  элемент. Hibernate будет генерировать необходимый уникальный ключ и ограничения неопределенности и, как результат, ваше сопоставление будет больше самодокументирован.

Рекомендуется выполнить equals() и hashCode() для сравнения естественные ключевые свойства объекта.

В коде, используя аннотации, это выглядит примерно так:

@Entity
public class UserRole {
  @Id
  @GeneratedValue
  private long id;

  @NaturalId
  private User user;
  @NaturalId
  private Role role;
}

Использование этого позволит вам сэкономить много головных болей по дороге, так как вы узнаете, когда вам часто приходится ссылаться/сопоставлять скомпилированный первичный ключ.

Я нашел это трудным путем и, в конце концов, просто отказался от борьбы с Hibernate и вместо этого решил пойти с потоком. Я полностью понимаю, что это может быть невозможно в вашем случае, поскольку вы, возможно, имеете дело с устаревшим программным обеспечением или зависимостями, но я просто хотел упомянуть об этом для будущей ссылки. (если вы не можете использовать его, может быть, кто-то еще может!)

Ответ 2

Чтобы выполнить ваше требование, вы можете сопоставить свой @ManyToMany как отображение @OneToMany. Таким образом, USER_ROLE будет содержать как USER_ID, так и ROLE_ID как составной первичный ключ

Я покажу вам, как:

@Entity
@Table(name="USER")
public class User {

    @Id
    @GeneratedValue
    private Integer id;

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

    // no-arg required constructor
    public User() {}

    public User(Integer id) {
        this.id = id;
    }

    // addRole sets up bidirectional relationship
    public void addRole(Role role) {
        // Notice a JoinedUserRole object
        JoinedUserRole joinedUserRole = new JoinedUserRole(new JoinedUserRole.JoinedUserRoleId(this, role));

        joinedUserRole.setUser(this);
        joinedUserRole.setRole(role);

        joinedUserRoleList.add(joinedUserRole);
    }

}

@Entity
@Table(name="USER_ROLE")
public class JoinedUserRole {

    public JoinedUserRole() {}

    public JoinedUserRole(JoinedUserRoleId joinedUserRoleId) {
        this.joinedUserRoleId = joinedUserRoleId;
    }

    @ManyToOne
    @JoinColumn(name="USER_ID", insertable=false, updatable=false)
    private User user;

    @ManyToOne
    @JoinColumn(name="ROLE_ID", insertable=false, updatable=false)
    private Role role;

    @EmbeddedId
    // Implemented as static class - see bellow
    private JoinedUserRoleId joinedUserRoleId;

    // required because JoinedUserRole contains composite id
    @Embeddable
    public static class JoinedUserRoleId implements Serializable {

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

        @ManyToOne
        @JoinColumn(name="ROLE_ID")
        private Role role;

        // required no arg constructor
        public JoinedUserRoleId() {}

        public JoinedUserRoleId(User user, Role role) {
            this.user = user;
            this.role = role;
        }

        public JoinedUserRoleId(Integer userId, Integer roleId) {
            this(new User(userId), new Role(roleId));
        }

        @Override
        public boolean equals(Object instance) {
            if (instance == null)
                return false;

            if (!(instance instanceof JoinedUserRoleId))
                return false;

            final JoinedUserRoleId other = (JoinedUserRoleId) instance;
            if (!(user.getId().equals(other.getUser().getId())))
                return false;

            if (!(role.getId().equals(other.getRole().getId())))
                return false;

            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 47 * hash + (this.user != null ? this.user.hashCode() : 0);
            hash = 47 * hash + (this.role != null ? this.role.hashCode() : 0);
            return hash;
        }

    }

}

помните,

Если объект имеет назначенный идентификатор или составной ключ, идентификатор ДОЛЖЕН БЫТЬ НАЗНАЧЕН экземпляр объекта ПЕРЕД вызовом save().

Итак, мы создали конструктор RegisteredUserRoleId, подобный этому, чтобы позаботиться об этом

public JoinedUserRoleId(User user, Role role) {
    this.user = user;
    this.role = role;
}

И, наконец, класс ролей

@Entity
@Table(name="ROLE")
public class Role {

    @Id
    @GeneratedValue
    private Integer id;

    @OneToMany(cascade=CascadeType.ALL, mappedBy="JoinedUserRoleId.role")
    private List<JoinedUserRole> joinedUserRoleList = new ArrayList<JoinedUserRole>();

    // no-arg required constructor
    public Role() {}

    public Role(Integer id) {
        this.id = id;
    }

    // addUser sets up bidirectional relationship
    public void addUser(User user) {
        // Notice a JoinedUserRole object
        JoinedUserRole joinedUserRole = new JoinedUserRole(new JoinedUserRole.JoinedUserRoleId(user, this));

        joinedUserRole.setUser(user);
        joinedUserRole.setRole(this);

        joinedUserRoleList.add(joinedUserRole);
    }

}

В соответствии с тестом, напишите следующее

User user = new User();
Role role = new Role();

// code in order to save a User and a Role
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();

Serializable userId  = session.save(user);
Serializable roleId = session.save(role);

session.getTransaction().commit();
session.clear();
session.close();

// code in order to set up bidirectional relationship
Session anotherSession = HibernateUtil.getSessionFactory().openSession();
anotherSession.beginTransaction();

User savedUser = (User) anotherSession.load(User.class, userId);
Role savedRole = (Role) anotherSession.load(Role.class, roleId);

// Automatic dirty checking
// It will set up bidirectional relationship
savedUser.addRole(savedRole);

anotherSession.getTransaction().commit();
anotherSession.clear();
anotherSession.close();

Обратите внимание на код выше NO REFERENCE на класс RegisteredUserRole.

Если вы хотите получить файл JoinUserRole, попробуйте следующее

Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();

Integer userId;
Integer roleId;

// Lets say you have set up both userId and roleId
JoinedUserRole joinedUserRole = (JoinedUserRole) session.get(JoinedUserRole.class, new JoinedUserRole.JoinedUserRoleId(userId, roleId));

// some operations

session.getTransaction().commit();
session.clear();
session.close();

С уважением,

Ответ 3

Композитные клавиши выполняются с помощью @IdClass (другой способ использует @EmbeddedId и @Embeddable не уверен, какой из них вы ищете) @IdClass выглядит следующим образом

@Entity
@IdClass(CategoryPK.class)
public class Category {
    @Id
    protected String name;

    @Id
    protected Date createDate;

}

public class CategoryPK implements Serializable {

    String name;

    Date createDate;

    public boolean equals(object other) {
        //implement a equals that the PP can use to determine 
        //how the CategoryPK object can be identified.
    }

    public int hashCode(){
        return Super.hashCode();
    }
}

Моя категория здесь будет вашим user_roles, а имя и createDate будет вашим идентификатором пользователя и ролей

Ответ 4

Спасибо за улучшение вашего вопроса... и с учетом предложений.

(Извините, немного странно, что вы отправляете свои объекты с помощью Daos, но это не так.)

Я не уверен, что осталась проблема:

  • Два объекта, которые вы описываете, имеют один ПК, а не пару.
  • Ссылка-таблица не имеет соответствующего объекта, она определяется неявно двумя объектами и их отношением ManyToMany. Если вам нужна третья сущность, измените свой ManyToMany на пару отношений OneToMany и ManyToOne.

Ответ 5

У меня была такая же проблема с первичными ключами. Я также знал решение с классом @Embeddable и @EmbeddedId. Но я хотел просто простое решение с аннотациями.

Ну, я нашел просветление в этой статье: http://www.vaannila.com/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html

и вот волшебство:

генерирует первичный ключ в таблице соединений:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="classA_classB")
private Set<ClassA> classesA;

это не приведет к генерации первичного ключа в таблице соединений:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="classA_classB")
private List<ClassA> classesA;

по крайней мере в моем окружении

Обратите внимание, что разница заключается в использовании Установить или Список