CRUD存储库不遵守UNIQUE约束条件。

10 浏览
0 Comments

CRUD存储库不遵守UNIQUE约束条件。

我有下面的JPA实体

@Entity
class UserEntity {
    companion object {
        fun fromParameters(uuid: String, email: String, password: String, firstName: String, lastName: String) =
            UserEntity().apply {
                this.uuid = uuid
                this.email = email
                this.password = password
                this.firstName = firstName
                this.lastName = lastName
            }
    }
    @Id
    lateinit var uuid: String
    @Column(nullable = false, unique = true)
    lateinit var email: String
    @Column(nullable = false)
    lateinit var password: String
    @Column(nullable = false)
    lateinit var firstName: String
    @Column(nullable = false)
    lateinit var lastName: String
}

这是用来检查唯一约束的测试,插入另一个使用相同电子邮件的用户。

@RunWith(SpringRunner::class)
@DataJpaTest
@AutoConfigureTestEntityManager
class TestUserCrudRepository {
    @Autowired
    private lateinit var userCrudRepository: UserCrudRepository
    private val testUserEntity = UserEntity.fromParameters(
        UUID.randomUUID().toString(),
        "test@test.com",
        "password".toHash(),
        "Caetano",
        "Veloso"
    )
    @Test
    fun `when email already exists it should throw error`() {
        with (userCrudRepository) {
            save(testUserEntity)
            val newUserEntity = with (testUserEntity) { UserEntity.fromParameters(UUID.randomUUID().toString(), email, password, firstName, lastName) }
            shouldThrow { save(newUserEntity) }
        }
    }
}

新实体总是会被插入具有重复电子邮件,而不会抛出任何异常。

Expected exception java.sql.SQLException but no exception was thrown

从日志中可以看到表格正确地创建了给定的约束。

Hibernate: drop table user_entity if exists
Hibernate: create table user_entity (uuid varchar(255) not null, email varchar(255) not null, first_name varchar(255) not null, last_name varchar(255) not null, password varchar(255) not null, primary key (uuid))
Hibernate: alter table user_entity add constraint UK_4xad1enskw4j1t2866f7sodrx unique (email)

提前谢谢!

admin 更改状态以发布 2023年5月22日
0
0 Comments

这是因为没有发出insert语句。

只有在有充分理由时,Hibernate才会flush会话。

  1. @DataJpaTest@Transactional,这意味着在@Test方法中执行的事务在方法返回后将回滚。
  2. UserEntity映射还鼓励Hibernate延迟insert(尝试在id属性上使用@GeneratedValue(strategy = IDENTITY)来强制发出insert

不需要深入了解这些测试运行时发生了什么:

  1. Spring的测试基础设施begin事务
  2. @Test方法运行
  3. save(testUserEntity) - Hibernate意识到没有理由与数据库交互并延迟insert
  4. shouldThrow {save(newUserEntity)} - 与上述相同
  5. @Test方法返回
  6. 回滚事务。Hibernate不执行insert,因为没有任何理由。

如何解决?

最简单的方法是使用JpaRepository#flush

with (userCrudRepository) {
    save(testUserEntity)
    val newUserEntity = with (testUserEntity) { UserEntity.fromParameters(UUID.randomUUID().toString(), email, password, firstName, lastName) }
    save(newUserEntity)
    assertThrows {
        flush()
    }
}

请注意,在CrudRepository中没有flush方法

我猜想您已经扩展了CrudRepository...您可能希望改为扩展JpaRepository

请参见:Spring Data JPA中CrudRepository和JpaRepository接口之间的区别是什么?


关于异常的说明

您希望引发SQLException

但是请注意,实际上会引发DataIntegrityViolationException

请参见:一致的异常层次结构

0