Spring JPA中的多对一关联不会更新相关实体

时间:2019-04-11 08:52:32

标签: java eclipselink many-to-one spring-repositories spring-boot-jpa

我在使用多对一关联将JPA实体插入数据库中时遇到问题。

我正在使用:

  • Spring Boot 2.1.4.RELEASE
  • Ecliselink 2.7.4.RC2(org.eclipse.persistence.jpa)
  • spring-boot-starter-data-jpa

我正在使用Spring的存储库,那里只有一个保存方法,没有插入,合并或更新方法。

我使用的实体SELECT t1.*, DATEDIFF(t1.date, t3.date) AS Difference FROM test t1 JOIN (SELECT UniqueId, MAX(Date) AS Date FROM test GROUP BY UniqueID) t2 ON t2.UniqueId = t1.UniqueId AND t2.Date = t1.Date LEFT JOIN test t3 ON t3.UniqueId = t1.UniqueId AND t3.Date = (SELECT MAX(Date) FROM test t4 WHERE t4.UniqueId = t3.UniqueId AND t4.Date < t2.Date) WHERE DATEDIFF(t1.date, t3.date) >= 10 与另一个实体ID UniqueId Date Difference T-3 AT-1 2018-04-22 13:05:16 12 T-6 AT-2 2018-05-25 06:09:23 10 具有多对一关联。

如果我用填充DbWatchlist的字段创建新的DbWatchlistProvider,一切正常。另外,如果我更改现有的DBWatchlist,并在此处更改DbWatchlistProvider的字段并进行保存,则一切正常。

但是,如果我尝试使用现有的DbWatchlist创建新的DbWatchlistProvider,则JPA总是尝试为DbWatchlist插入新记录。

在插入实体DbWatchlistProvider之前,我尝试从数据库中读取DbWatchlistProvider,然后进行保存,但是在此还完成了INSERT。这将导致异常:

DbWatchlistProvider

我的代码:

DbWatchlist

在测试中,我尝试了以下操作:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: unique constraint or index violation; SYS_PK_10144 table: WATCHLISTPROVIDER
Error Code: -104
Call: INSERT INTO WatchlistProvider (Key, Description, Id) VALUES (?, ?, ?)
bind => [3 parameters bound]

直到最后一次保存,所有操作均正常进行,并且没有错误,并且与预期的一样。 有人知道问题出在什么地方,为什么要插入@Entity @Table(name = TableName.WATCHLIST, uniqueConstraints = { @UniqueConstraint(columnNames = {ColumnName.PROVIDER_KEY, ColumnName.ID})}) @UuidGenerator(name = KEY_GENERATOR) public class DbWatchlist { @Id @Column(name = ColumnName.KEY, nullable = false) @GeneratedValue(generator = KEY_GENERATOR) public String key; @ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = ColumnName.PROVIDER_KEY, nullable = false, updatable = false) public DbWatchlistProvider watchlistProvider; @Column(name = ColumnName.ID, nullable = false) public String id; @Column(name = ColumnName.DESCRIPTION) public String description; @Column(name = ColumnName.LATEST_VERSION) public String latestVersion; } @Entity @Table(name = TableName.PROVIDER, uniqueConstraints = { @UniqueConstraint(columnNames = {ColumnName.ID})}) @UuidGenerator(name = KEY_GENERATOR) public class DbWatchlistProvider { @Id @Column(name = ColumnName.KEY, nullable = false) @GeneratedValue(generator = KEY_GENERATOR) public String key; @Column(name = ColumnName.ID, nullable = false) public String id; @Column(name = ColumnName.DESCRIPTION) public String description; } @Repository public interface WatchlistRepository extends CrudRepository<DbWatchlist, String> { boolean existsByWatchlistProviderAndId(DbWatchlistProvider provider, String id); } 而不更新吗?

例外是:

DbWatchlistProvider provider = new DbWatchlistProvider();
provider.id = "PROV";
provider.description = "description for provider";

DbWatchlist newRow = new DbWatchlist();
newRow.id = "ID1";
newRow.description = "description";
newRow.watchlistProvider = provider;

DbWatchlist createdRow = repository.save(newRow);

createdRow.description = "update";
createdRow.watchlistProvider.description = "also updated";
createdRow = repository.save(createdRow);

DbWatchlist createdRow2 = new DbWatchlist();
createdRow2.watchlistProvider = createdRow.watchlistProvider;
createdRow2.id = "test";
createdRow2.description = "description";

//This save is not working, but the createdRow2.watchlistProvider.key is filled
repository.save(createdRow2);

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题,最近发现了根本原因。

就我而言,问题是我有两个@Entity类引用相同的@Table(name = X)

当发生这样的事情时,您必须同时更新两个实体,否则就会收到错误消息,就像在这里看到的一样。

(在我的情况下)解决方案是使用DTO投影,而不是为一个表使用重复的实体。

简单修复,但是错误导致方式混乱,而不是清晰性。

不知道您是否遇到相同的问题,但是您确实有相同的错误。

HTH!