【问题标题】:Spring Data JPA inserting instead of UpdateSpring Data JPA 插入而不是更新
【发布时间】:2014-12-28 04:05:20
【问题描述】:

嗨,我是 Spring Data JPA 的新手,我想知道即使我将 Id 传递给实体,Spring 数据 jpa 是插入而不是合并。我想当我实现Persistable接口并实现这两个方法时:

public Long getId();
public Boolean isNew();

它会自动合并而不是持久化。

我有一个名为 User like 的实体类:

@Entity
@Table(name = "T_USER")
public class User implements Serializable, Persistable<Long> {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "USER_ID")
   private Long id;

   @Column(name = "CREATION_TIME", nullable = false)
   private Date creationTime;

   @Column(name = "FIRST_NAME", nullable = false)
   private String firstName;

   @Column(name = "LAST_NAME", nullable = false)
   private String lastName;

   @Column(name = "MODIFICATION_TIME", nullable = false)
   private Date modificationTime;

还有一门课

@Entity
@Table(name = "T_USER_ROLE")
public class UserRole implements Serializable, Persistable<Long> {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long roleId;

   @Column(name = "ROLE_NAME")
   private String userRole;
}

我有一个名为 UserRepostory 的自定义存储库,它扩展了 JpaReopistory。我正在保存合并和持久化,因为我看到实现表明 Spring Data Jpa 使用上述两种方法来更新或插入。

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

我一直在试图弄清楚,但没有得到任何线索。可能是你 小伙伴们可以帮忙。

【问题讨论】:

  • 你不需要实现持久化接口。只需使用继承的save,Spring Data 就会为您处理。
  • @Rana_S 你是如何解决这个问题的?我有一个非常相似的问题:why saveAll() always inserts data instead of update it?
  • @catch23 我在数据库中有版本列,在实体字段上标记了@Version,在持久化时丢失了。所以必须填充版本字段并工作。看到你的帖子,尝试添加版本列,看看它是如何反应的。此外,建议实施更好的 equalshashCode 而不仅仅是 id。
  • @Rana_S 感谢您的回复。试过这种方法。抛出相同的异常。但是,版本参数始终为空 - 因为它是从远程获取的,并且未显示此字段。因此,实体总是被视为“新”
  • @catch23 所以你是说你有版本栏?如果是这样,那么 Spring 将对此进行评估。看看这个saving Entities Strategies。如果你没有使用版本,那么删除就可以了。

标签: spring jpa spring-data-jpa


【解决方案1】:

我遇到了这个问题,尝试实现Persistable 无济于事,然后查看了 Spring Data JPA 源。我不一定会在您的示例代码中看到这一点,但我的实体中有一个 @Version 字段。如果有 @Version 字段 Spring Data 将测试 that 值以确定实体是否是新的。如果@Version 字段不是原语并且为空,则该实体被视为新实体。

这让我在测试中丢了很长时间,因为我没有在我的表示中设置版本字段,而只是在持久实体上设置。我也没有在其他有用的 Spring Data 文档中看到这一点(这是另一个问题......)。

希望对某人有所帮助!

【讨论】:

  • 是的,你是对的。我在实体中有版本字段。我从来不知道 Spring Data JPA 会寻找那个字段。
  • 感谢您的回答我遇到了同样的问题!
  • 关于 @Version 的问题,我通过添加 Java Validation @Null 注释、为版本字段分配低默认值并删除版本字段的设置器来解决这个问题.这样该字段永远不会为空。我使用 Instant 类作为 @Version 字段。
【解决方案2】:

默认情况下,Spring Data JPA 检查给定实体的标识符属性。如果标识符属性是null,那么实体将被假定为新的,否则为非新的。我是Id-Property inspectionReference

如果您将 Spring JPA 与 EntityManager 一起使用,则调用 .merge() 将更新您的实体,.persist() 将插入。

@PersistenceContext
private EntityManager em;

@Override
@Transactional
public User save(User user) {

    if (user.getId() == null) {
        em.persist(user);
        return user;
    } else {
        return em.merge(user);
    }
}

无需实现Persistable 接口。

【讨论】:

  • 谢谢@njjnex。但是当您使用 JpaRepository 接口并从 Service 类调用 save 方法时,您会看到 Spring Data JPA 在内部检查实体是否是新的。这样当一个实体实现 Spring 的 Persistable 接口时,它会覆盖两个方法:1. Boolean isNew() 和 2. Long getId()。但它不起作用。
  • 正如我所说,我正在进入 Spring Data Jpa 并且以前使用过自己的自定义 dao 层。我通过在 dao 实现中传递 entityManager 来完成您上面提到的方式。这很好,但我的问题是为什么它在 Spring data Jpa 的上下文中不起作用。
猜你喜欢
  • 2018-11-25
  • 1970-01-01
  • 1970-01-01
  • 2016-09-12
  • 2016-07-21
  • 2018-01-13
  • 1970-01-01
  • 2019-09-05
  • 2015-05-15
相关资源
最近更新 更多