Сопоставление объектов Hibernate «один ко многим»: идентификаторы для этого класса должны быть назначены вручную перед вызовом save ()

Я new bee in Hibernate и использую PostgreSQL 9.3, JDK 1.7, Hibernate 4.0.2

Я пытаюсь сохранить отношение Customer who Has-a с Address, то есть отношение One-To-Many.

Сопоставления базы данных

При сохранении Customer я получаю исключение:

javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.cust.entities.Address

Субъект-заказчик:

@Entity
@Table(name="customer")
public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name = "CustomerIdSeq", sequenceName = "c_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CustomerIdSeq")
    @Column (name="c_id")
    private Long cId;

    @Column(name="cname")
    private String cname;

    //bi-directional many-to-one association to Address
    @OneToMany(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn(name="c_id")
    private List<Address> address;

    //getters and setters

    }

Адрес объекта:

    @Entity
    @Table(name="address")
    public class Address {

        @Id
        @Column(name="c_id")
        private Long cId;

        @ManyToOne
        @PrimaryKeyJoinColumn(name="c_id", referencedColumnName="c_id")
        private Customer customer; 

        @Column(name="street")
        private String street;

        @Column (name="city")
        private String city;

        //getters and setters
      public void setCustomer(Customer customer) {
           this.customer= customer;
           this.cId= customer.getCId();
       }

        }

Я пробовал что-то похожее на Java Persistence/Identity & Sequencing


person 09Q71AO534    schedule 22.12.2014    source источник


Ответы (2)


Я подозреваю, что запись адреса не имеет идентификатора при вызове save().

Вам не хватает тега @GeneratedValue в этом классе, и если он не указан, по умолчанию он имеет «назначенное» значение.

Если вы не присвоите значение Address.cId перед вызовом save(), вы увидите эту проблему. Опубликуйте весь соответствующий код, если это не является причиной проблемы.

РЕДАКТИРОВАТЬ: Глядя на структуру вашей таблицы, адрес действительно должен иметь свой собственный идентификатор в дизайне схемы и иметь ссылку внешнего ключа (FK) на Customer.ID.

person Dave    schedule 22.12.2014
comment
Спасибо за ответ :). А пока рассмотрим дизайн, как он определен выше. Не может ли адресная сущность использовать тот же ключ, что и клиент. Я знаю, что дизайн еще не является хорошей практикой - person 09Q71AO534; 22.12.2014
comment
Разве у нас нет @аннотаций для достижения такого отношения «один ко многим» между клиентом и адресом? - person 09Q71AO534; 22.12.2014
comment
Без адреса, имеющего собственный идентификатор, нет смысла использовать спящий режим (я даже не уверен, что это вообще возможно). Поскольку Hibernate использует идентификатор каждого объекта, чтобы найти его в кеше и т. д. - person Dave; 22.12.2014
comment
Тогда почему мы можем сделать это в режиме взаимного сопоставления, поскольку это здесь Это какая-то ограниченная функциональность в Has-a Relation. Направь меня, если я думаю неправильно - person 09Q71AO534; 22.12.2014
comment
У телефона есть OwnerID, у Address есть OwnerID, у PhonePK есть идентификатор типа, и из того, что я вижу во всем примере кода по этой ссылке, все переменные ID назначаются до вызова save(). Ваша проблема в том, что вы пытаетесь использовать назначенный идентификатор, не присваивая значение перед вызовом save(). Проверьте самую нижнюю часть вашей ссылки, чтобы узнать, где Address не имеет PK (сгенерируйте идентификатор во время выполнения). - person Dave; 22.12.2014
comment
Я обновил установщик в Address Entity, но все же исключение остается там. Мне все ясно, за исключением того, что мне нужно установить его перед сохранением: P. Я хочу обработать этот сценарий в Hibernate. - person 09Q71AO534; 22.12.2014
comment
Выложите полный код реализации. Держу пари, что customer.getCId() возвращает null в момент вызова. - person Dave; 22.12.2014
comment
Без адреса, имеющего собственный идентификатор, нет смысла использовать спящий режим (я даже не уверен, что это вообще возможно). Объект, не имеющий собственной постоянной идентичности, может быть отображен как встраиваемый. - person Alan Hay; 22.12.2014
comment
Не может ли адресная сущность использовать тот же ключ, что и клиент. Как это будет работать, если у клиента может быть › 1 адрес? Разве у нас нет никаких @аннотаций для достижения такого отношения «один ко многим» между клиентом и адресом. Да, см. ответ, предлагающий «@Embeddable». - person Alan Hay; 22.12.2014

Сформируйте комментарии к предыдущему ответу и из существующей структуры таблицы, вы можете рассмотреть возможность сопоставления Address как Embeddable, а не как Entity:

Это похоже на OneToMany, за исключением того, что целевой объект является Embeddable, а не Entity. Это позволяет легко определять наборы простых объектов, не требуя, чтобы простые объекты определяли обратное сопоставление Id или ManyToOne. ElementCollection также может переопределять сопоставления или таблицу для их коллекции, поэтому вы можете иметь несколько объектов, ссылающихся на один и тот же класс Embeddable, но каждый из которых хранит свои зависимые объекты в отдельной таблице.

http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection

Тогда отображения будут следующими. Адрес не будет иметь собственного постоянного идентификатора и может существовать только как часть объекта — в настоящее время клиента, но нет причин, по которым вы не можете использовать его с другими объектами, которым требуется адрес.

Покупатель:

@Entity
@Table(name="customer")
public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name = "CustomerIdSeq", sequenceName = "c_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CustomerIdSeq")
    @Column (name="c_id")
    private Long cId;

    @Column(name="cname")
    private String cname;

    @ElementCollection
    @CollectionTable(name = "customer_address", joinColumns = @JoinColumn(name = "c_id")
    private List<Address> addresses;
}

Адрес:

@Embeddable
public class Address {

    @Column(name="street")
    private String street;

    @Column (name="city")
    private String city;
}
person Alan Hay    schedule 22.12.2014
comment
Это то, что я ищу. Я попробую это и обновлю вас. Спасибо за ответ :) - person 09Q71AO534; 22.12.2014
comment
@AlanHay, вы можете посмотреть на этот вопрос /27602318/ пожалуйста? - person VB_; 22.12.2014