Hibernate : not-null property references a null or transient value

18,241

Keep it simple :

public class MovieInformation {
    private ReleaseCompany releaseCompany;
    private Rating rating;
    // Other data member
    // Constructor, getter and setter
    public ReleaseCompany getReleaseCompany(){
        return releaseCompany;
    }
    public Rating getRating(){
        return rating;
    }
    public void setReleaseCompany(ReleaseCompany releaseCompany){
        this.releaseCompany = releaseCompany;
    }
}

public class ReleaseCompany {
    private int releaseCompanyId;
    private String releaseCompanyName;

    private Set<MovieInformation> movies = new HashSet<MovieInformation>();

    public ReleaseCompany(){
    }
    public ReleaseCompany(String releaseCompanyName){
        this.releaseCompanyName = releaseCompanyName;
    }

    public ReleaseCompany(ReleaseCompany releaseCompany){
        this.releaseCompanyName = releaseCompany.getReleaseCompanyName();
    }
    public Set<MovieInformation> getMovies() {  
        return movies;  
    }  
    private void setMovies(Set<MovieInformation> movies) {  
        this.movies = movies;
    }  
    // Other constructor, getter and setter
}

public class Rating {
    private MovieInformation movie;
    // other data member

    public void setMovie(MovieInformation movie){
        this.movie = movie;
    }
    // other constructor, getter and setter
}

Please note that setMovies(Set movies) is private, so the only way to change all movies is to do something like this:

releaseCompany.getMovies().clear();
releaseCompany.getMovies().addAll(newMovieCollection);

You need to that because:

  • hibernate need to track the changes made to the collection
  • hibernate put a proxy around the collection to do this tracking.
  • replacing the Set by another one implies that the hibernate proxy will be lost
Share:
18,241
Biboo Chung
Author by

Biboo Chung

Student of computer science

Updated on June 28, 2022

Comments

  • Biboo Chung
    Biboo Chung almost 2 years

    Problem Solved. Thank you.

    Now I have three tables movie_information, release_company and rating. movie_information and rating are having one-to-one relationship while release_company and movie_information are having one-to-many relationship. I am trying to build a CMS with hibernate but I found that I am not able to correctly construct the part that involve these three tables.

    Here comes my code

    MovieInformation.java

    public class MovieInformation {
        private ReleaseCompany releaseCompany;
        private Rating rating;
        // Other data member
        // Constructor, getter and setter
        public ReleaseCompany getReleaseCompany(){
            ReleaseCompany newReleaseCompany = new ReleaseCompany(this.releaseCompany);
            return newReleaseCompany;
        }
        public Rating getRating(){
            Rating newRating = new Rating(this.rating);
            return newRating;
        }
        public void setReleaseCompany(ReleaseCompany releaseCompany){
            this.releaseCompany = new ReleaseCompany(releaseCompany);
        }
    }
    

    ReleaseCompany.java

    public class ReleaseCompany {
        private int releaseCompanyId;
        private String releaseCompanyName;
    
        private Set<MovieInformation> movies = new HashSet<MovieInformation>();
    
        public ReleaseCompany(){
        }
        public ReleaseCompany(String releaseCompanyName){
            this.releaseCompanyName = releaseCompanyName;
        }
        public ReleaseCompany(ReleaseCompany releaseCompany){
            this.releaseCompanyName = releaseCompany.getReleaseCompanyName();
        }
        public Set<MovieInformation> getMovies() {  
            Set<MovieInformation> newMoviesSet = new HashSet<MovieInformation>(movies);
            return newMoviesSet;  
        }  
        public void setMovies(Set<MovieInformation> movies) {  
            this.movies = new HashSet<MovieInformation>(movies);
        }  
        // Other constructor, getter and setter
    }
    

    Rating.java

    public class Rating {
        private MovieInformation movie;
        // other data member
    
        public void setMovie(MovieInformation movie){
            this.movie = new MovieInformation(movie);
        }
        // other constructor, getter and setter
    }
    

    MovieInformation.hbm.xml

    <class name="cart.hibernate.movieInformation.MovieInformation" table="movie_information">
        <id column="move_id" name="movieId" type="long">
            <generator class="native"/>
        </id>
    
        <one-to-one name="rating" class="cart.hibernate.rating.Rating" cascade="save-update"></one-to-one> 
    
        <many-to-one name="releaseCompany" class="cart.hibernate.releaseCompany.ReleaseCompany"  unique="false"><!-- constrained="true" -->
            <column name="release_company_id" not-null="true" />
        </many-to-one>
        // Other property
    </class>
    

    Rating.hbm.xml

    <class name="cart.hibernate.rating.Rating" table="rating">
      <id name="movieId" type="java.lang.Long">
          <column name="movie_id" />
          <generator class="foreign">
              <param name="property">movie</param>
          </generator>
      </id>
    
      <property column="avg_rate" name="avgRate" type="double"/>
      <property column="num_of_rate" name="numOfRate" type="long"/>
    
      <one-to-one name="movie" class="cart.hibernate.movieInformation.MovieInformation" constrained="true"></one-to-one>
    </class>
    

    ReleaseCompany.hbm.xml

    <class name="cart.hibernate.releaseCompany.ReleaseCompany" table="release_company">
        <id column="release_company_id" name="releaseCompanyId" type="int">
            <generator class="native"/>
        </id>
        <property column="release_company_name" name="releaseCompanyName" type="string"/>
    
        <set name="movies" table="movie_information" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="movie_id" not-null="true" />
            </key>
            <one-to-many class="cart.hibernate.movieInformation.MovieInformation" />
        </set>
    </class>
    

    Testing Main method

    Session session = HibernateUtil.getSessionFactory().openSession();
    Transaction tx = null;
    tx = session.beginTransaction();
    
    Rating rating = new Rating(5.6, 80);
    ReleaseCompany releaseCompany = new ReleaseCompany();
    releaseCompany.setReleaseCompanyName("a");
    session.save(releaseCompany);        
    
    //  ReleaseCompany releaseCompany = (ReleaseCompany)session.get(ReleaseCompany.class, 15); 
    //  Another testing case that I have tried. It throw another exception,
    //  if you need the information in this part, please let me know.
    
    MovieInformation movie = new MovieInformation("Matrix", 150, 1, 50, date, releaseDate, "good description");
    movie.setRating(rating);
    movie.setReleaseCompany(releaseCompany);
    
    rating.setMovie(movie);
    
    session.save(movie);  // <--- Error occur here
    tx.commit();
    

    StackTrace

    org.hibernate.PropertyValueException: not-null property references a null or transient value: cart.hibernate.movieInformation.MovieInformation.releaseCompany
        at org.hibernate.engine.Nullability.checkNullability(Nullability.java:100)
        at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:312)
        at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
        at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
        at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
        at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
        at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:713)
        at org.hibernate.impl.SessionImpl.save(SessionImpl.java:701)
        at org.hibernate.impl.SessionImpl.save(SessionImpl.java:697)
        at cart.hibernate.movieInformation.ManageMovieInformation.main(ManageMovieInformation.java:61)
    BUILD SUCCESSFUL (total time: 1 second)
    

    I have read several similar question, some of the people said the releaseCompany(in my case) object hasn't saved to the database so the setReleaseCompany() cannot work as expected. I am not sure whether the releaseCompany object exist or not because I cannot see the record in MySql(I am not sure whether the record would be saved or not if exceptions are thrown). Moreover, some of them said the attribute of the mapping tag is not correct but I am not sure whether mine are correct or not.

    I apologies to put so much code in the post, hope that you could solve this problem.