复合主键导致org.hibernate.NonUniqueObjectException

时间:2015-04-30 17:56:35

标签: hibernate

我正在尝试使用表City的复合主键,如果它没有被分配给Country,那么它应该不存在(它应该是多对的...一个识别关系)。

我的问题首先是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例外:

完整的堆栈跟踪:

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#com.mahlzeit.datamodel.address.City$CityId@8a62f66]
    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 个答案:

答案 0 :(得分:1)

对于City类,主键为CityId,此类有2个属性 - id&amp; country

请注意@GeneratedValue仅在该属性也使用@Id注释时才有用,因此GeneratedValueid属性的添加CityId无效在类中,hibernate将忽略它。此外,您无法为此属性添加@Id,因为此类代表@Embeddable

现在,在您的程序中,您正在设置CityId,如下所示:

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

CityId的构造函数是:

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

所以最后你要创建两个同一个国家的城市:

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

另外,由于您没有为id类的CityId设置值,因此它始终为null。所以city对象graz和&amp; wien具有相同的主键,因为country参考&amp; id(在这种情况下为null)。

此外,您需要在您的实体之间进行适当的映射,请参阅此SO帖子以获取类似示例:

How to Represent Composite keys in Hibernate using Annotations?

来到id的{​​{1}}属性,您必须明确设置,否则它将始终为CityId