问题
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