JPA Spring CrudRepository TransientObjectException

时间:2017-09-07 12:24:33

标签: java spring hibernate spring-data-jpa

我希望使用Spring Data JPA管理人员,团队及其成员资格。 以下测试(whenAddingANewTeamTroughPerson)

  1. 在我使用entityManager.persist(alex);
  2. 时通过 如果我使用personRepository.save(alex);
  3. 会抛出异常

    为什么呢?在后一种情况下,我得到以下异常:

    org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: hello.data.model.Person; nested exception is java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: hello.data.model.Person
    

    表现为CASCADE未正确设置。但它必须是正确的,因为它适用于entityManager。

    PersonRepositoryTest:

    @RunWith(SpringRunner.class)
    @DataJpaTest
    public class PersonRepositoryTest {
    
        @Autowired
        private TestEntityManager entityManager;
    
        @Autowired
        private PersonRepository personRepository;
    
        @Autowired
        private TeamRepository teamRepository;
    
        @Test
        public void whenFindOne_thenReturnPerson() {
            // given
            Person alex = new Person("alex");
            entityManager.persist(alex);
            entityManager.flush();
    
            // when
            Person found = personRepository.findOne(alex.getId());
    
            // then
            assertThat(found.getName(), equalToIgnoringWhiteSpace(alex.getName()));
        }
    
        @Test
        public void whenAddingANewTeamTroughPerson_thenNoException() {
            // given
            Person alex = new Person("alex");
            Team t = new Team("team");
            alex.addTeam(t, "integrationTest", new Date());
            personRepository.save(alex);
            //entityManager.persist(alex);
    
            // when
            Person found = personRepository.findOne(alex.getId());
    
            // then
            assertThat(found.getTeams().size(), is(1));
        }
    
    }
    

    PersonRepository:

    public interface PersonRepository extends CrudRepository<Person, Integer> {}
    

    人:

    @Entity
    public class Person {
        private static final Logger LOG = LoggerFactory.getLogger(Person.class);
        private final IntegerProperty id = new SimpleIntegerProperty(this, "id");
        private final StringProperty name = new SimpleStringProperty(this, "name");
        private Set<PersonTeam> personTeams = new LinkedHashSet<>();
    
        private ListProperty<Team> teams = new SimpleListProperty<>(this, "teams", FXCollections.observableArrayList());
    
        public Person(String s) {
            this.name.set(s);
        }
    
        public Person() {}
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        public Integer getId() {
            return id.get();
        }
    
        public void setId(Integer id) {
            this.id.set(id);
        }
        public IntegerProperty idProperty() {
            return id;
        }
        @Basic
        @Column(name = "name")
        public String getName() {
            return name.get();
        }
        public void setName(String name) {
            this.name.set(name);
        }
        public StringProperty nameProperty() {
            return name;
        }
    
        @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.person", cascade=CascadeType.ALL, orphanRemoval = true)
        public Set<PersonTeam> getPersonTeams() {
            return personTeams;
        }
    
        public void setPersonTeams(Set<PersonTeam> personTeams) {
            this.personTeams = personTeams;
            teams.setAll(personTeams.stream().map(PersonTeam::getTeam).collect(Collectors.toList()));
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            Person person = (Person) o;
    
            if (getId() != null ? !getId().equals(person.getId()) : person.getId() != null) return false;
            if (getName() != null ? !getName().equals(person.getName()) : person.getName() != null) return false;
    
            return true;
        }
    
        @Override
        public int hashCode() {
            int result = id != null ? id.hashCode() : 0;
            result = 31 * result + (getName() != null ? getName().hashCode() : 0);
            return result;
        }
    
        /**
         * Returns an Observable List that must remain unchanged.
         * Unfortunately there is no RO Observable List Interface to refer to.
         */
        @Transient
        public ObservableList<Team> getTeams() {
            return teams.get();
        }
    
        @Transient
        public ReadOnlyListProperty<Team> teamsProperty() {
            return teams;
        }
    
        public void addTeam(Team team, String createdBy, Date createdDate) {
            final PersonTeam personTeam = new PersonTeam(this, team);
            personTeam.setCreatedBy(createdBy);
            personTeam.setCreatedDate(createdDate);
            if( !personTeams.add(personTeam) ) {
                LOG.error("Failed to add personTeam " + personTeam + " to collection personTeams " + personTeams);
            }
            if( !team.getPersonTeams().add( personTeam ) ) {
                LOG.error("Failed to add personTeam " + personTeam + " to collection team.getPersonTeams " + team.getPersonTeams());
            }
            teams.setAll(personTeams.stream().map(PersonTeam::getTeam).collect(Collectors.toList()));
        }
    
        public void removeTeam(Team team) {
            PersonTeam personTeam = new PersonTeam( this, team );
            team.getPersonTeams().remove( personTeam );
            personTeams.removeIf( pt -> pt.getTeam() == team );
            personTeam.setPerson( null );
            personTeam.setTeam( null );
            teams.setAll(personTeams.stream().map(PersonTeam::getTeam).collect(Collectors.toList()));
        }
    
        /*
          The method is not intended to be used in the GUI.
          Use the {@link GUIRepresentable} interface instead.
         */
        @Override
        public String toString() {
            return name.getValue();
        }
    
    }
    

    PersonTeam:

    @Entity
    @Table(name = "person_team")
    @AssociationOverrides({
        @AssociationOverride(name = "pk.person",
            joinColumns = @JoinColumn(name = "PERSON_ID")),
        @AssociationOverride(name = "pk.team",
            joinColumns = @JoinColumn(name = "TEAM_ID")) })
    public class PersonTeam implements java.io.Serializable {
    
        private PersonTeamPk pk = new PersonTeamPk();
        private Date createdDate;
        private String createdBy;
    
        public PersonTeam() {
        }
    
        public PersonTeam(Person person, Team team) {
            this.pk.setPerson(person);
            this.pk.setTeam(team);
        }
    
        @EmbeddedId
        public PersonTeamPk getPk() {
            return pk;
        }
    
        public void setPk(PersonTeamPk pk) {
            this.pk = pk;
        }
    
        @Transient
        public Person getPerson() {
            return getPk().getPerson();
        }
    
        public void setPerson(Person person) {
            getPk().setPerson(person);
        }
    
        @Transient
        public Team getTeam() {
            return getPk().getTeam();
        }
    
        public void setTeam(Team team) {
            getPk().setTeam(team);
        }
    
        @Temporal(TemporalType.DATE)
        @Column(name = "CREATED_DATE", nullable = false, length = 10)
        public Date getCreatedDate() {
            return this.createdDate;
        }
    
        public void setCreatedDate(Date createdDate) {
            this.createdDate = createdDate;
        }
    
        @Column(name = "CREATED_BY", nullable = false, length = 10)
        public String getCreatedBy() {
            return this.createdBy;
        }
    
        public void setCreatedBy(String createdBy) {
            this.createdBy = createdBy;
        }
    
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;
    
            PersonTeam that = (PersonTeam) o;
    
            if (getPk() != null ? !getPk().equals(that.getPk())
                : that.getPk() != null)
                return false;
    
            return true;
        }
    
        public int hashCode() {
            return (getPk() != null ? getPk().hashCode() : 0);
        }
    
    }
    

    PersonTeamPk:

    @Embeddable
    public class PersonTeamPk implements java.io.Serializable {
    
        private Person person;
        private Team team;
    
        @ManyToOne(cascade = CascadeType.ALL)
        public Person getPerson() {
            return person;
        }
    
        public void setPerson(Person person) {
            this.person = person;
        }
    
        @ManyToOne(cascade = CascadeType.ALL)
        public Team getTeam() {
            return team;
        }
    
        public void setTeam(Team team) {
            this.team = team;
        }
    
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            PersonTeamPk that = (PersonTeamPk) o;
    
            if (person != null ? !person.equals(that.person) : that.person != null) return false;
            if (team != null ? !team.equals(that.team) : that.team != null)
                return false;
    
            return true;
        }
    
        public int hashCode() {
            int result;
            result = (person != null ? person.hashCode() : 0);
            result = 31 * result + (team != null ? team.hashCode() : 0);
            return result;
        }
    
    }
    

    小组:

    @Entity
    public class Team implements Serializable, Comparable<Team>  {
        private final IntegerProperty id = new SimpleIntegerProperty(this, "id");
        private final StringProperty name = new SimpleStringProperty(this, "name");
        private Set<PersonTeam> personTeams = new LinkedHashSet<>();
    
        public Team(String s) {
            this.name.set(s);
        }
    
        public Team() {}
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        public Integer getId() {
            return id.get();
        }
    
        public void setId(Integer id) {
            this.id.set(id);
        }
        public IntegerProperty idProperty() {
            return id;
        }
        @Basic
        @Column(name = "name")
        public String getName() {
            return name.get();
        }
        public void setName(String name) {
            this.name.set(name);
        }
        public StringProperty nameProperty() {
            return name;
        }
    
        @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.team", orphanRemoval = true, cascade = CascadeType.ALL)
        public Set<PersonTeam> getPersonTeams() {
            return personTeams;
        }
    
        public void setPersonTeams(Set<PersonTeam> personTeams) {
            this.personTeams = personTeams;
        }
    
        public static Callback<Team, Observable[]> extractor() {
            return (Team p) -> new Observable[]{p.nameProperty()};
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            Team team = (Team) o;
    
            if (getId() != null ? !getId().equals(team.getId()) : team.getId() != null) return false;
            if (getName() != null ? !getName().equals(team.getName()) : team.getName() != null) return false;
    
            return true;
        }
    
        @Override
        public int hashCode() {
            int result = id != null ? id.hashCode() : 0;
            result = 31 * result + (getName() != null ? getName().hashCode() : 0);
            return result;
        }
    
        @Override
        public String toString() {
            return name.getValue();
        }
    
        @Override
        public int compareTo(Team o) {
            return Integer.compare(getId(), o.getId());
        }
    }
    

0 个答案:

没有答案