避免对Hibernate / Spring JPA的原始痴迷

vx6bjr1n  于 4个月前  发布在  Spring
关注(0)|答案(1)|浏览(79)

在我们的Sping Boot 3(Kotlin)项目中,我们应用了域驱动设计,并希望在实体和存储库中avoid primitive obsession(尤其是ID,通常是类型为x1的,很容易混淆)。使用@Embeddable / @EmbeddedId将原始ID类型 Package 在一个类中是个好主意吗?像这样:

@Embeddable
data class OrderId(var orderId: String = "") : Serializable

@Entity
data class Order(
    @EmbeddedId
    var id: OrderId = OrderId(),
)

字符串
(We我们只见过这种方法用于复合键。)或者其他一些机制是推荐的方法吗?我们担心微妙的陷阱,例如,它可能不完全兼容JPQL原生查询。

0tdrvxhp

0tdrvxhp1#

我的项目使用了一个自定义的UUID(https://github.com/ulid/spec的Kotlin派生),我们使用它作为所有实体的标识符。实际上,我们并没有为每个实体使用不同的UUID,但这很容易实现。
我们不使用@EmbeddedId,而只是配置到Spring Data序列化过程中的一个东西。
这意味着实体类在正常情况下不需要注解任何东西:

data class Channel(
    val id: RULID,
    ...
}

字符串
因为,至少在Mongo中,id是预期的主键(当它到达Mongo DB时被翻译为_id)。
下面是相关的代码片段(假设RULID是我们的自定义ID)-正如您所看到的,我们在数据库端将其序列化为String。

@org.springframework.data.convert.ReadingConverter
class DBObjectToRULIDConverter : Converter<String, RULID> {
    override fun convert(source: String): RULID {
        if (!RULID.isValid(source)) {
            return RULID.INVALID
        }
        return RULID.from(source)
    }
}

@org.springframework.data.convert.WritingConverter
class RULIDToDBObjectConverter : Converter<RULID, String> {
    override fun convert(source: RULID): String {
        return source.toString()
    }
}


考虑到我们使用的是Mongo,我们这样声明转换器:

@Configuration
@EnableMongoRepositories(basePackages = ["xxxxxxx.yyyyyy"])
class MongoConfig {

    @Bean
    fun customConversions(): MongoCustomConversions {
        return MongoCustomConversions(
            listOf(
                DBObjectToRULIDConverter(),
                RULIDToDBObjectConverter(),
                // others...
            )
        )
    }
}


Spring Repository接口魔术在许多情况下无需任何配置即可工作:

@Repository
interface ProfileRepository : MongoRepository<Profile, RULID>


没有任何额外的东西,因此findById(id: RULID): Profile无需进一步配置即可工作。
和自定义查询,再次工作,没有任何进一步的序列化处理:

@Query("{'member._id': ?0}")
    fun findChannelsByUserId(memberId: RULID?): List<Channel>


或编写较低级别的查询语法:

val criteria = Criteria.where("_id").`is`(channel.id)

相关问题