Spring Data JPA(休眠):更新复杂对象,首选惯用法

时间:2018-06-22 15:55:54

标签: hibernate jpa

使用Spring Data JPA和Hibernate更新复杂实体的首选惯用法是什么? 我在两种方法之间犹豫不决,也许还有更多我还不知道的方法:

  1. 休眠方式:1)通过Id加载带有惰性集合和子对象的整个复杂对象; 2)通过设置新值来更新其已更改的字段,3)让Hibernate通过@DynamicUpdate
  2. 应用动态查询
  3. 下降到SQL本机查询。

在这两种情况下,我仅更新核心实体(基本上仅更新其原始字段),而不更新子对象和集合,而在其他位置和方法分别对其进行更新。

优点和缺点:

  1. 优点:简单易行,准确更新已更改的内容缺点:在实际更新之前必须加载整个对象(两个查询), Hibernate生成的许多准备好的语句供@DymanicUpdate使用;

  2. 优点: 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);
}

因此,我想弄清楚什么是行之有效的默认方法?您将在项目中采用哪种方法?谢谢你。

0 个答案:

没有答案