使用Spring Data JPA和Hibernate更新复杂实体的首选惯用法是什么? 我在两种方法之间犹豫不决,也许还有更多我还不知道的方法:
在这两种情况下,我仅更新核心实体(基本上仅更新其原始字段),而不更新子对象和集合,而在其他位置和方法分别对其进行更新。
优点和缺点:
优点:简单易行,准确更新已更改的内容缺点:在实际更新之前必须加载整个对象(两个查询), Hibernate生成的许多准备好的语句供@DymanicUpdate使用;
优点: 1个查询(完全用于更新),所有操作都是可控的缺点:手动操作方式,输入的手动验证,不仅更新内容改变了。
为直观显示我正在处理的内容,以下是代码:
@Entity
@Table(name = "question")
@DynamicUpdate
public class Question {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
@Column(name = "question_id")
protected Long questionId;
@Column(name = "title")
@Size(min = 10, max = 200, message = "About Me must be between 10 and 200 characters")
private String question;
@Column(name = "level")
private byte level;
@Column(name = "is_deleted")
private boolean deleted;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "theme_id", updatable = false)
private Theme theme;
@ManyToOne
@JoinColumn(name = "type_id", insertable = false, updatable = false)
private QuestionType type;
@ManyToOne
@JoinColumn(name = "lang_id")
private Language lang;
@OneToOne(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)
private Help help;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "question_resource", joinColumns = @JoinColumn(name = "question_id"), inverseJoinColumns = @JoinColumn(name = "resource_id"))
private Set<Resource> resources = new HashSet<>();
DAO:
public interface QuestionRepository extends CrudRepository<Question, Long> {
@Modifying
@Query(value="update question set title = ?2, level= ?3, lang_id=?4 where question_id = ?1", nativeQuery = true)
void updateById(long questionId, String title, byte level, long langId);
}
服务:
@Transactional
public void update(@NonNull Question newQuestion) {
final Question oldQuestion;
try {
oldQuestion = questionRepository.findById(newQuestion.getQuestionId()).get();
} catch (NoSuchElementException e) {
throw new RuntimeException("Question not found");
}
oldQuestion.setQuestionId(newQuestion.getQuestionId());
oldQuestion.setQuestion(newQuestion.getQuestion());
oldQuestion.setLevel(newQuestion.getLevel());
if (newQuestion.getLang()!=null) oldQuestion.setLang(newQuestion.getLang());
log.info("Updated question :: {} ", oldQuestion);
}
@Transactional
public void updateNative(long questionId, String title, byte level, long langId) {
if (questionId<=0 || title==null || title.isEmpty() || level<1 || level>3 || langId<=0 )
throw new RuntimeException("Invalid input");
questionRepository.updateById(questionId, title, level, langId);
log.info("Updated question :: {} ", questionId);
}
因此,我想弄清楚什么是行之有效的默认方法?您将在项目中采用哪种方法?谢谢你。