【问题标题】:Many-To-One Association in Spring JPA does not update related entitySpring JPA中的多对一关联不更新相关实体
【发布时间】:2019-04-11 08:52:32
【问题描述】:

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

我正在使用:

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

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

我使用一个实体 DbWatchlist,它与另一个实体 DbWatchlistProvider 具有多对一关联。

如果我创建一个新的DBWatchlist 并填充了DbWatchlistProvider 的字段,那么一切正常。此外,如果我更改现有的 DbWatchlist 以及此处的 DbWatchlistProvider 字段并保存一切正常。

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

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

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);

直到最后一次保存,一切正常,没有错误,正如预期的那样。 有人知道问题出在哪里,为什么DbWatchlistProvider 试图插入而不更新?

例外是:

Caused by: 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]

Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.DatabaseException

Query: InsertObjectQuery

Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: unique constraint or index violation; SYS_PK_10144 table: WATCHLISTPROVIDER

Caused by: org.hsqldb.HsqlException: integrity constraint violation: unique constraint or index violation; SYS_PK_10144 table: WATCHLISTPROVIDER

【问题讨论】:

  • 在将新的 DbWatchlistProvider 实例设置为 DbWatchlist 实例并合并之前,是否已为其分配了主键?
  • 是的,密钥已设置

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


【解决方案1】:

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

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

当您发生这种情况时,您必须同时更新两个实体,否则您会收到像您在此处看到的错误。

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

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

不知道你是否有同样的问题,但你确实有同样的错误。

HTH!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-07
    • 1970-01-01
    • 1970-01-01
    • 2013-01-03
    相关资源
    最近更新 更多