CrudRepository.save() appears to cascade

跟風遠走 提交于 2021-01-28 22:55:30

问题


Entity Survey:

    @Entity
    @Table(name = "Survey")
    public class Survey implements Serializable {

        private Long id;
        private String name;
        private String address;
        private List<Question> questions;

        @Id
        @Column(name = "id")
        public Long getId() {
            return id;
        }

        @Column(name = "name")
        public String getName() {
            return name;
        }

        @Column(name = "address")
        public String getAddress() {
            return address;
        }

        @OneToMany(fetch = FetchType.LAZY, mappedBy = "survey")
        public List<Question> getQuestions() {
            return questions;
        }

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

        public void setName(final String name) {
            this.name = name;
        }

        public void setAddress(final String address) {
            this.address = address;
        }

        public void setQuestions(List<Question> _questions) {
            this.questions = _questions;
        }
    }

Question Entity:

@Entity
@Table(name = "Question")
public class Question {

    private Long id;
    private String question;
    private Survey survey;

    @Id
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    @Column(name = "question")
    public String getQuestion() {
        return question;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "survey_id")
    public Survey getSurvey() {
        return survey;
    }

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

    public void setQuestion(String question) {
        this.question = question;
    }

    public void setSurvey(Survey survey) {
        this.survey = survey;
    }
}

Question Crud Repo:

 public interface QuestionRepo extends CrudRepository<Question, Long> {
    }

Controller:

@RestController
@RequestMapping("/default")
public class DefaultEndpoint {

    @Autowired
    private QuestionRepo questionRepo;


    @PostMapping(value = "/saveQuestion")
    public void saveQuestion(@Param("id") Long id, @Param("question") String question, @Param("survey_id") Long survey_id) {
        Question questionObject = new Question();
        questionObject.setId(id);
        questionObject.setQuestion(question);
        Survey survey = surveyRepo.findById(survey_id).get();
        survey.setName("example");
        questionObject.setSurvey(survey);
        questionRepo.save(questionObject);
    }
}

In the Controller snippet, when I do survey.setName("example");. this change is reflected on the database.

It means that save() operation, which is implemented with EntityManager methods MERGE and PERIST, cascades to the child entity even if no Cascade type is specified.
Is this how it is supposed to work, or am I doing some stupid mistake ?
Thanks a lot !


回答1:


Please check @ManyToOne annotation to see that the default cascade is none.

public @interface ManyToOne {
   /**
     * (Optional) The operations that must be cascaded to 
     * the target of the association.
     *
     * <p> By default no operations are cascaded.
     */
    CascadeType[] cascade() default {};
}

There is no cascading taking place.

Most likely, the effect you are observing is a combination of 2 features:

  • Dirty Checking
  • Open Session In View.

If you are running a web application, Spring Boot by default registers OpenEntityManagerInViewInterceptor to apply the “Open EntityManager in View” pattern, to allow for lazy loading in web views. If you do not want this behavior, you should set spring.jpa.open-in-view to false in your application.properties.

Dirty Checking is quite well known, but Open Session In View tends to be a surprise for some devs (For example, see another related effect in Spring - Same entity detached on the @EventListener but attached in the @Service class)




回答2:


It's the dirty checking mechanism. E.g when you flush persistence context or commit transaction Hibernate checks the context for the dirty state of entities and executes SQL update to synchronize in-memory with the database state. You can check this post to get more detail



来源:https://stackoverflow.com/questions/60675809/crudrepository-save-appears-to-cascade

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!