默认情况下,我理解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,因为这对我来说并不重要。有没有办法在不必向服务类添加逻辑的情况下执行此操作?
答案 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
...但是,等等,不是那么简单,但是并不难。只需执行以下步骤:
NaturalRepository
界面:@NoRepositoryBean
interface NaturalRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
Optional<T> findBySimpleNaturalId(ID naturalId);
}
@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;
}
}
@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class)
class MySpringApp {
...
@NaturalId
注释您的字段:@Entity
public class BookEntity {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@NaturalId
@Column(name = "isbn")
private String isbn;
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
...
@Autowired
BookRepository repository;
...
String isbn = "...";
try {
Book book = repository.findBySimpleNaturalId(isbn).get();
book.author = "gal";
repository.save(book);
} catch(NoSuchElementException notfound) {
...
}
令人高兴的是,您可以在任何其他项目中或与其他表的任何其他存储库中复用NaturalRepository
和NaturalRepositoryImpl
。