简体   繁体   English

休眠ManyToOne保存对象

[英]Hibernate ManyToOne saving objects

I am having a problem with saving an entity with ManyToOne Bidirectional relationship, here it is: 我在保存具有ManyToOne双向关系的实体时遇到问题,这里是:

WARN: HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. 警告:HHH000437:尝试保存一个或多个与未保存的临时实体具有不可为空关联的实体。 The unsaved transient entity must be saved in an operation prior to saving these dependent entities. 在保存这些从属实体之前,必须将未保存的临时实体保存在操作中。 Unsaved transient entity: ([com.epam.apartmentsbooking.model.City#912]) Dependent entities: ([[com.epam.apartmentsbooking.model.Apartment#640]]) Non-nullable association(s): ([com.epam.apartmentsbooking.model.Apartment.city]) 未保存的临时实体:([com.epam.apartmentsbooking.model.City#912])从属实体:([[com.epam.apartmentsbooking.model.Apartment#640]])不可空关联:([com .epam.apartmentsbooking.model.Apartment.city])

org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : com.epam.apartmentsbooking.model.Apartment.city -> com.epam.apartmentsbooking.model.City org.hibernate.TransientPropertyValueException:非null属性引用一个瞬态值-必须在当前操作之前保存瞬态实例:com.epam.apartmentsbooking.model.Apartment.city-> com.epam.apartmentsbooking.model.City

This may seem common but I cannot save an entity that references existing city in the database. 这似乎很常见,但是我无法在数据库中保存引用现有城市的实体。

Here is my code 这是我的代码

Apartment.java: Apartment.java:

package com.epam.apartmentsbooking.model;

import java.io.Serializable;

/**
 * <p>
 * Class describes the apartment entity
 */
public class Apartment implements Serializable {

private Long id;
private String name;
private String accommodationType;
private Byte numberOfGuests;
private Byte numberOfBedrooms;
private Byte numberOfBathrooms;
private Float pricePerDay;
private Float square;
private Short floor;
private String description;
private City city;


/**
 * Default constructor of the class
 * Should be used only when properties will be set later
 */
public Apartment() {
    id = -1L;
    name = "Default name";
    accommodationType = null;
    numberOfGuests = 0;
    numberOfBedrooms = 0;
    numberOfBathrooms = 0;
    pricePerDay = 0F;
    square = 0F;
    floor = 0;
    description = "Default description";
    city = new City();
}

/**
 * Counstructor that fully makes the object, should be used in most cases
 *
 * @param id                ID of the apartment
 * @param name              Name of the apartment
 * @param accommodationType Accommodation type (House, Apartment, Studio Apartment)
 * @param numberOfGuests    Maximum number of guests that host can place in the apartment
 * @param numberOfBedrooms  Number of bedrooms in the apartment
 * @param numberOfBathrooms Number of bathrooms in the apartment
 * @param pricePerDay       Price per day for the apartment
 * @param square            Square of the apartment (in sq. m.)
 * @param floor             Floor on which apartment is located
 * @param description       Description of the apartment
 * @param city              City where apartment is located
 */
public Apartment(Long id, String name, String accommodationType, Byte numberOfGuests, //NOSONAR
                 Byte numberOfBedrooms, Byte numberOfBathrooms, Float pricePerDay, Float square, Short floor,
                 String description, City city) {
    this.id = id;
    this.name = name;
    this.accommodationType = accommodationType;
    this.numberOfGuests = numberOfGuests;
    this.numberOfBedrooms = numberOfBedrooms;
    this.numberOfBathrooms = numberOfBathrooms;
    this.pricePerDay = pricePerDay;
    this.square = square;
    this.floor = floor;
    this.description = description;
    this.city = city;
}

/**
 * @return the id of the apartment
 */
public Long getId() {
    return id;
}

/**
 * @param id id of the apartment to be set
 */
public void setId(Long id) {
    this.id = id;
}

/**
 * @return the name of the apartment
 */
public String getName() {
    return name;
}

/**
 * @param name the name to be set
 */
public void setName(String name) {
    this.name = name;
}

/**
 * @return Accommodation type of the apartment
 */
public String getAccommodationType() {
    return accommodationType;
}

/**
 * @param accomodationType accommodationType to be set
 */
public void setAccommodationType(String accomodationType) {
    this.accommodationType = accomodationType;
}

/**
 * @return the maximum number of guest that may be placed in the apartment
 */
public Byte getNumberOfGuests() {
    return numberOfGuests;
}

/**
 * @param numberOfGuests number of guests to be set
 */
public void setNumberOfGuests(Byte numberOfGuests) {
    this.numberOfGuests = numberOfGuests;
}

/**
 * @return the number of bedrooms
 */
public Byte getNumberOfBedrooms() {
    return numberOfBedrooms;
}

/**
 * @param numberOfBedrooms the number of bedrooms to be set
 */
public void setNumberOfBedrooms(Byte numberOfBedrooms) {
    this.numberOfBedrooms = numberOfBedrooms;
}

/**
 * @return the number of bathrooms
 */
public Byte getNumberOfBathrooms() {
    return numberOfBathrooms;
}

/**
 * @param numberOfBathrooms the number of bathrooms to be set
 */
public void setNumberOfBathrooms(Byte numberOfBathrooms) {
    this.numberOfBathrooms = numberOfBathrooms;
}

/**
 * @return the price of stay per day
 */
public Float getPricePerDay() {
    return pricePerDay;
}

/**
 * @param pricePerDay the price to be set
 */
public void setPricePerDay(Float pricePerDay) {
    this.pricePerDay = pricePerDay;
}

/**
 * @return the square of the apartment in square meters
 */
public Float getSquare() {
    return square;
}

/**
 * @param square square of the apartment to be set
 */
public void setSquare(Float square) {
    this.square = square;
}

/**
 * @return floor number of the apartment
 */
public Short getFloor() {
    return floor;
}

/**
 * @param floor number of floor to be set
 */
public void setFloor(Short floor) {
    this.floor = floor;
}

/**
 * @return the description of the apartment
 */
public String getDescription() {
    return description;
}

/**
 * @param description description to be set
 */
public void setDescription(String description) {
    this.description = description;
}

/**
 * @return the city of the apartment
 */
public City getCity() {
    return city;
}

/**
 * @param city city to be set
 */
public void setCity(City city) {
    this.city = city;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Apartment apartment = (Apartment) o;

    if (!id.equals(apartment.id)) return false;
    if (!name.equals(apartment.name)) return false;
    if (accommodationType.equals(apartment.accommodationType)) return false;
    if (!numberOfGuests.equals(apartment.numberOfGuests)) return false;
    if (!numberOfBedrooms.equals(apartment.numberOfBedrooms)) return false;
    if (!numberOfBathrooms.equals(apartment.numberOfBathrooms)) return false;
    if (!pricePerDay.equals(apartment.pricePerDay)) return false;
    if (!square.equals(apartment.square)) return false;
    if (!floor.equals(apartment.floor)) return false;
    if (!description.equals(apartment.description)) return false;
    return city.equals(apartment.city);
}

@Override
public int hashCode() {
    int result = id.hashCode();
    result = 31 * result + name.hashCode();
    result = 31 * result + accommodationType.hashCode();
    result = 31 * result + numberOfGuests.hashCode();
    result = 31 * result + numberOfBedrooms.hashCode();
    result = 31 * result + numberOfBathrooms.hashCode();
    result = 31 * result + pricePerDay.hashCode();
    result = 31 * result + square.hashCode();
    result = 31 * result + floor.hashCode();
    result = 31 * result + description.hashCode();
    result = 31 * result + city.hashCode();
    return result;
}

@Override
public String toString() {
    return "Apartment{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", accomodationType=" + accommodationType +
            ", numberOfGuests=" + numberOfGuests +
            ", numberOfBedrooms=" + numberOfBedrooms +
            ", numberOfBathrooms=" + numberOfBathrooms +
            ", pricePerDay=" + pricePerDay +
            ", square=" + square +
            ", floor=" + floor +
            ", description='" + description + '\'' +
            ", city=" + city +
            '}';
}

} }

City.java: City.java:

package com.epam.apartmentsbooking.model;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 * <p>
 * Class describes city entity
 */
public class City implements Serializable {

private Long id;
private String name;
private Country country;
private Set<Apartment> apartments = new HashSet<>();

/**
 * Default constructor
 * Preferable not to use
 */
public City() {
    id = 912L;
    name = "Minsk";
    country = new Country();
}

/**
 * Creates new city object
 * Should be used in most cases
 *
 * @param id      Id of the city
 * @param name    Name of the city
 * @param country ISO Code of the country
 */
public City(Long id, String name, Country country) {
    this.id = id;
    this.name = name;
    this.country = country;
}

/**
 * @return the name of the city
 */
public String getName() {
    return name;
}

/**
 * @param name The name of the city to be set
 */
public void setName(String name) {
    this.name = name;
}

/**
 * @return Country object which the city is references on
 */
public Country getCountry() {
    return country;
}

/**
 * @param country Country object to set
 */
public void setCountry(Country country) {
    this.country = country;
}

/**
 * @return id of the city
 */
public Long getId() {
    return id;
}

/**
 * @param id id to be set
 */
public void setId(Long id) {
    this.id = id;
}

public Set<Apartment> getApartments() {
    return apartments;
}

public void setApartments(Set<Apartment> apartments) {
    this.apartments = apartments;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    City city = (City) o;

    if (id != null ? !id.equals(city.id) : city.id != null) return false;
    if (name != null ? !name.equals(city.name) : city.name != null) return false;
    if (country != null ? !country.equals(city.country) : city.country != null) return false;
    return apartments != null ? apartments.equals(city.apartments) : city.apartments == null;
}

@Override
public int hashCode() {
    int result = id != null ? id.hashCode() : 0;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    result = 31 * result + (country != null ? country.hashCode() : 0);
    result = 31 * result + (apartments != null ? apartments.hashCode() : 0);
    return result;
}

@Override
public String toString() {
    return "City{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", country=" + country +
            ", apartments=" + apartments +
            '}';
}

} }

ApartmentDaoImpl.java: ApartmentDaoImpl.java:

package com.epam.apartmentsbooking.dao.impl.hibernate;

import com.epam.apartmentsbooking.dao.ApartmentDao;
import com.epam.apartmentsbooking.model.Apartment;
import com.epam.apartmentsbooking.model.City;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;

/**
 *
 * Apartment DAO Implementation
 *
 * @see com.epam.apartmentsbooking.dao.ApartmentDao
 */
@Repository("apartmentDaoHibernate")
@Transactional
public class ApartmentDaoImpl extends GenericDaoImpl<Apartment, Long> implements ApartmentDao {

@Autowired
@Qualifier("sessionFactory")
private SessionFactory sessionFactory;

@Override
public Long create(Apartment newInstance) {

    return (Long) sessionFactory.getCurrentSession().save(newInstance);

}

@Override
public Apartment getByName(String name) {
    Query query = sessionFactory.getCurrentSession().createQuery("from Apartment where name=:name");
    query.setParameter("name", name);
    return (Apartment) query.uniqueResult();
}

@Override
public Collection<Apartment> getAll() {

    return sessionFactory.getCurrentSession().createCriteria(Apartment.class).list();
}

@Override
public Collection<Apartment> filter(String name, String accommodationType, Byte numberOfGuests,
                                    Byte numberOfBedrooms, Byte numberOfBathrooms, Float pricePerDay,
                                    Long cityId) {

    Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Apartment.class);

    criteria.add(Restrictions.ilike("name", name + "%"));
    criteria.add(Restrictions.ilike("accommodationType", accommodationType + "%"));
    criteria.add(Restrictions.ge("numberOfGuests", numberOfGuests));
    criteria.add(Restrictions.ge("numberOfBedrooms", numberOfBedrooms));
    criteria.add(Restrictions.ge("numberOfBathrooms", numberOfBathrooms));
    criteria.add(Restrictions.le("pricePerDay", pricePerDay));
    criteria.add(Restrictions.eq("city.id", cityId));

    return criteria.list();
}

} }

Test Case 测试用例

    @Test
    @ExpectedDatabase("/apartments-test-create.xml")
    public void testCreate() {
        Apartment newApartment = new Apartment(null, "Test Apartment#4", "STUDIO", (byte) 3, (byte) 3, (byte) 3,
                400F, 78F, (short) 4, "EPAM Studio #2", new City());

        apartmentDao.create(newApartment);
    }

In your Apartment class, you have to tell hibernate that it is OK to cascade the commit to the 'City' object as well. 在Apartment类中,您必须告诉休眠状态,也可以将提交落实到“ City”对象。 You can do this by adding the @Cascade annotation to the City object like this: 您可以通过将@Cascade批注添加到City对象来实现,如下所示:

@Cascade({ org.hibernate.annotations.CascadeType.ALL })
private City city;

Now when you persist the Apartment, that will also persist City at the same time. 现在,当您保留公寓时,这还将同时保留城市。

Alternatively, first persist your 'city' object, then use the persisted city object to build the Apartment object. 或者,首先持久化“ city”对象,然后使用持久化的city对象构建Apartment对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM