2015-04-30 3 views
0

Я пытаюсь использовать составной первичный ключ для таблицы City, которая не должна существовать, если она не назначена на Country (предполагается, к-одному идентифицирующая связь).Композитный первичный ключ ведет к org.hibernate.NonUniqueObjectException

Моя проблема заключается в первую очередь, что ChildId (см вложенный класс) имеет @GeneratedValue что null после инициализирую Child как здесь:

List<City> cityList = new ArrayList<>();  
City graz = new City(austria, "Graz"); 
// Runs without exceptions but graz.getCityId().getId() will be 'null' 
cityList.add(graz); 
cityList.add(new City(austria, "Wien")); 

Все это, кажется, что из-за этого я получаю org.hibernate.NonUniqueObjectException исключение :

Полный StackTrace:

Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.mahlzeit.datamodel.address.City#[email protected]] 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182) 
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:138) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:204) 
    at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:189) 
    at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49) 
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90) 
    at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:642) 
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:635) 
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:631) 
    at com.mahlzeit.datamodel.HibernateTest.addAddressData(HibernateTest.java:63) 
    at com.mahlzeit.datamodel.HibernateTest.populateDatabase(HibernateTest.java:35) 
    at com.mahlzeit.datamodel.HibernateTest.main(HibernateTest.java:31) 

Я не знайте, могу ли я сделать это таким образом. Если да, как я могу это сделать?

City.java

@Entity 
public class City implements Serializable { 

    private static final long serialVersionUID = -4374113410767348574L; 

    @EmbeddedId 
    private CityId cityId; 

    private String cityName; 

    public City(Country country, String cityName) { 
     setCityId(new CityId(country)); 
     this.cityName = cityName; 
    } 

    public String getCityName() { 
     return cityName; 
    } 

    public void setCityName(String countryName) { 
     this.cityName = countryName; 
    } 

    public CityId getCityId() { 
     return cityId; 
    } 

    public void setCityId(CityId cityId) { 
     this.cityId = cityId; 
    } 

    @Embeddable 
    public static class CityId implements Serializable{ 

     private static final long serialVersionUID = -8561021314776406519L; 

     @GeneratedValue 
     private Long id; 

     private Country country; 

     public CityId(Country country) { 
      this.setCountry(country); 
     } 

     public Long getId() { 
      return id; 
     } 

     public void setId(Long id) { 
      this.id = id; 
     } 

     public Country getCountry() { 
      return country; 
     } 

     public void setCountry(Country country) { 
      this.country = country; 
     }  
    } 
} 

Country.java

@Entity 
public class Country implements Serializable { 

    private static final long serialVersionUID = -2060021861139912774L; 

    @Id 
    @GeneratedValue 
    private Long id; 

    @Column(unique=true) 
    private String countryCode; 

    public Country(String country_code) { 
     this.countryCode = country_code; 
    } 

    public String getCountryCode() { 
     return countryCode; 
    } 

    public void setCountryCode(String countryCode) { 
     this.countryCode = countryCode; 
    } 

    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 
} 

ответ

1

Для City класса первичный ключ CityId и этот класс имеет 2 свойства - id & country.

Пожалуйста, обратите внимание, что @GeneratedValue полезна только тогда, когда свойство также помечается @Id, поэтому нет никакого смысла добавлять GeneratedValue для id собственности в CityId класса, спящий режим будет просто игнорировать это. Кроме того, вы не можете добавить @Id для этого объекта, поскольку этот класс представляет @Embeddable

Теперь в программе вы устанавливаете CityId так:

public City(Country country, String cityName) { 
    setCityId(new CityId(country)); 
    this.cityName = cityName; 
} 

Конструктор CityId является:

public CityId(Country country) { 
     this.setCountry(country); 
    } 

Так наконец, вы создаете 2 города с одной страной:

City graz = new City(austria, "Graz"); 
new City(austria, "Wien"); 

Также, поскольку вы не устанавливаете значение для id класса CityId, оно всегда будет null. Таким образом, оба объекта citygraz & wien имеют одинаковый первичный ключ из-за комбинации country. Ссылка & id (в этом случае это нуль).


Кроме того, необходимо иметь правильное соответствие между вашими лицами, относятся к этому SO опубликовать для подобного примера:

How to Represent Composite keys in Hibernate using Annotations?

Coming к id собственности CityId, вы должны установить, что в явном виде или он всегда будет null.

+0

Ну да, но как бы я сгенерировал 'CityId.id'? Это просто * имеет *, чтобы как-то автогенерировать, как '@ Id'. Как мне это сделать? Я не хочу, чтобы я устанавливал его явно, потому что мне пришлось бы искать себя, если это значение все еще доступно или нет. Должен быть способ использования автоматически сгенерированного (или автоматического прироста) значения. – displayname

+0

@StefanFalk, мой ответ о том, почему вы получаете эту проблему, и исправить это, вы должны явно указать этот идентификатор, автоматическое создание не будет работать , Но я вижу, что у вас уже есть отдельный вопрос: http://stackoverflow.com/questions/29976363/hibernate-generatedvalue-in-embedded-always-null, а steve и дать ответ, попробовали ли вы эту опцию. – Chaitanya

+0

Нет, я не был на машине, но я попробую это через несколько часов, когда я туда доберусь. Я приму ваш ответ здесь. Если хотите, я могу сообщить, могу ли я решить проблему id и как это сделать. :) – displayname

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