2015-06-28 3 views
5

Мне нужно иметь дружеские отношения. У меня есть класс дружбы с двумя первичными ключами, каждый из которых является классом-членом. Я получаю следующее исключение:Как смоделировать отношения дружбы в спящем режиме?

org.hibernate.MappingException: Foreign key (FK_8ynretl1yt1xe3gcvfytrvpq:Friendship [])) must have same number of columns as the referenced primary key (Member [username]) 

Дружба

@Entity 
public class Friendship implements Serializable { 
    /** 
    * 
    */ 
    private static final long serialVersionUID = -1234656876554786549L; 
    @Id 
    @ManyToOne 
    Member requester; 
    @Id 
    @ManyToOne 
    Member friend; 
    @Temporal(javax.persistence.TemporalType.DATE) 
Date date; 

Член

@Entity 
public class Member { 
    @Id 
    @MapsId 
    @OneToOne(cascade = CascadeType.ALL) 
    @JoinColumn(name = "username") 
    Credential credential; 
    @Column(nullable = false) 
    String fname; 
    @Column(nullable = false) 
    String lname; 
    @Column(nullable = false) 
    short gender; 

Credential

@Entity 
public class Credential { 
    @Id 
    @Column(nullable = false, unique = true) 
    private String username; 
    @Column(nullable = false) 
    private String password; 
    @Column(nullable = false) 
    private String authority; 
    @Column(nullable = false) 
    private boolean enabled; 

ответ

1

Отложив что Member и Credential должны осуществлять Serializable, если используются несколько свойств идентификаторов без типа идентификатора, ваши отображения хорошо, и это, кажется, ошибка в Hibernate.

Решение 1

мне удалось сделать эту работу, объявив referencedColumnName в friend и requester ассоциации в Friendship:

@Id 
@ManyToOne 
@JoinColumn(referencedColumnName = "username") 
Member requester; 

@Id 
@ManyToOne 
@JoinColumn(referencedColumnName = "username") 
Member friend; 

Таким образом, мы явно указать Hibernate, какие столбцы композитные ссылки ID, так что он не должен сам это выяснять.

Решение 2

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

Так что я изменил порядок, в котором я добавить аннотированные классы к заводской конфигурации сеанса для:

Credential 
Member 
Friendship 

, а затем все работало с оригинальными отображений (после реализации Serializable в Member и Credential).

Я добавил классы в таком порядке программно в Configuration классе, но я предполагаю, что тот же эффект может быть достигнут путем определения этого порядка в persistence.xml или hibernate.cfg.xml:

<class>Credential</class> 
<class>Member</class> 
<class>Friendship</class> 

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

Примечание

Вы знаете свои варианты использования лучше, но, по моему личному мнению, вы должны использовать @IdClass или @EmbeddedId, поскольку они стандартизованы в JPA; множественные свойства id без типа идентификатора - это специальная функция Hibernate. Помимо возможности упростить создание объекта первичного ключа, по которому вы будете искать и запрашивать соответствующие объекты, выделенный объект PK обычно намного легче и обеспечивает лучшую производительность при сериализации, особенно если включен кеш второго уровня.

1

Для обозначения @MapsID вы должны добавить отдельное поле идентификатора в поле Member. Как это:

@Entity 
public class Member implements Serializable { 
    @Id 
    private String username; 

    @MapsId 
    @OneToOne(cascade = CascadeType.ALL) 
    @JoinColumn(name = "username") 
    Credential credential; 
    @Column(nullable = false) 
    String fname; 
    @Column(nullable = false) 
    String lname; 
    @Column(nullable = false) 
    short gender; 

} 
0

Friendship В классе попробуйте указать на @JoinColumn, а также:

@Entity 
public class Friendship implements Serializable { 

    @Id 
    @ManyToOne 
    @JoinColumn(name = "username") 
    Member requester; 

    ... 
} 
+0

Я сделал, но он возвращает внешний ключ, ссылающийся на com.myproject.model.Member из com.myproject.model.Friendship имеет неправильное количество столбцов. должно быть 0 – Jack

0

Вы пропускаете моделирование первичного ключа в Friendship классе. Например:

@Embeddable 
public class FriendshipPK implements Serializable 
{ 
    @Column(name = "requester_id") 
    protected String requesterId; 

    @Column(name = "friend_id") 
    protected String friendId; 
} 

класс Friendship теперь может быть изменен следующим образом:

@Entity 
public class Friendship implements Serializable 
{ 
    @EmbeddedId 
    protected FriendshipPK friendshipId = new FriendshipPK(); 

    @ManyToOne 
    @MapsId("requesterId") 
    Member requester; 

    @ManyToOne 
    @MapsId("friendId") 
    Member friend; 

    @Temporal(javax.persistence.TemporalType.DATE) 
    Date date; 
} 

Я немного обновил класс пользователя:

@Entity 
public class Member implements Serializable 
{ 
    @Id 
    protected String memberId; 

    @MapsId 
    @OneToOne(optional = false) 
    @JoinColumn(name = "username") 
    Credential credential; 
    @Column(nullable = false) 
    String fname; 
    @Column(nullable = false) 
    String lname; 
    @Column(nullable = false) 
    short gender; 
} 

Я удалил каскад из класса членов, и сначала создавали объекты учетных данных. Но вы можете изменить это как нужное.

Смежные вопросы