Spring hibernate CrudRepository根据唯一约束使save方法更新

时间:2018-06-15 11:42:44

标签: java hibernate spring-boot

默认情况下,我理解CrudRepository.save方法是根据主键插入和更新的。

考虑以下实体

@Entity
public class BookEntity {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    @Basic
    @Column(name = "isbn", unique = true)
    private String isbn;

    @Basic
    @Column(name = "title")
    private String title;

    @Basic
    @Column(name = "author")
    private String author;

    @Basic
    @Column(name = "publication_date")
    private Date publicationDate;

    @Basic
    @Column(name = "rank")
    private Integer rank;
}

因为我不能在表格中找到相同的isbn书籍而且我不想担心生成ID我通常会将以下json发布到一个点上

{ "isbn": "10932011", "title": "harry", "author": "jk", "publicationDate": "2018-10-10", "rank": 1000 }

使用自动生成的ID

返回以下内容

{ "id": 3, "isbn": "10932011", "title": "harry", "author": "jk", "publicationDate": "2018-10-10T00:00:00.000+0000", "rank": 1000 }

如果我使用相同的isbn进行第二次呼叫,我将收到约束错误

{ "isbn": "10932011", "title": "harry", "author": "jk3", "publicationDate": "2018-10-10", "rank": 1000 }

但我想用同样的isbn更新这本书,而不必在帖子json中指定自动生成的id,因为这对我来说并不重要。有没有办法在不必向服务类添加逻辑的情况下执行此操作?

3 个答案:

答案 0 :(得分:2)

您可以获取BookEntity,更改并保存。

由于您的isbn是唯一的,您可以执行以下操作:

BookEntity book = bookRepository.findByIsbn(isbn);
book.setWhateverFieldYouWant(value);
bookRepository.save(book);.

或其他解决方案

您可以在@Query中使用BookRepository注释创建方法:

@Query("UPDATE BookEntity b SET b.whateverField = :value WHERE b.isbn = :isbn")
void updateBook(@Param("value") String value, @Param("isbn") String isbn);

并从服务中调用它:

bookRepository.updateBook(value, isbn);

答案 1 :(得分:1)

由于您使用的是Hibernate,您还可以查看一下Hibernate提供的NaturalId API。除了生成的ID之外,您还要将isbn注释为@NaturalId,然后使用NaturalId API检索您的图书。

@Entity
public class BookEntity {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    @NaturalId
    @Column(name = "isbn")
    private String isbn;

加载示例:

BookEntity book = entityManager.unwrap(Session.class)
.bySimpleNaturalId(BookEntity.class)
.load("your isbn goes here");

有关NaturalIds的进一步阅读,请查看 this article(其示例为isbns)或this one

NaturalIds的一大优点是你可以从hibernate缓存机制中受益。

答案 2 :(得分:0)

我发现的最好方法是基于in this article using @NaturalId

它的工作原理是将CrudRepository替换为JpaRepository ...但是,等等,不是那么简单,但是并不难。只需执行以下步骤:

1。创建一个NaturalRepository界面:

@NoRepositoryBean
interface NaturalRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
    Optional<T> findBySimpleNaturalId(ID naturalId);
}

2。创建此类接口的实现:

@Transactional(readOnly = true)
class NaturalRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements NaturalRepository<T, ID> {
    final EntityManager entityManager;

    NaturalRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    @Override
    Optional<T> findBySimpleNaturalId(ID naturalId) {
        Optional<T> entity = entityManager.unwrap(Session.class)
                .bySimpleNaturalId(this.getDomainClass())
                .loadOptional(naturalId);
        return entity;
    }
}

3。在您的Spring应用程序中启用它:

@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class)
class MySpringApp {
...

4。用@NaturalId注释您的字段:

@Entity
public class BookEntity {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    @NaturalId
    @Column(name = "isbn")
    private String isbn;

5。转换您的CrudRepository界面:

@Repository
interface BookRepository extends NaturalRepository<Book, String> {
    // You can add other methods here like:
    List<Book> findByTitle(String title);
    List<Book> findByAuthor(String author);
}

请确保:

  • 它现在使用@Repository(而不是@RepositoryRestResource
  • 现在应该扩展NaturalRepository(而不是CrudRepository)
  • 第二种类型应为String

6。最后,您可以将其用作:

...
@Autowired
BookRepository repository;
...
String isbn = "...";
try {
    Book book = repository.findBySimpleNaturalId(isbn).get();
    book.author = "gal";
    repository.save(book);
} catch(NoSuchElementException notfound) {
    ...
}

令人高兴的是,您可以在任何其他项目中或与其他表的任何其他存储库中复用NaturalRepositoryNaturalRepositoryImpl