如何告诉SpringDataMongoDB将文档的嵌套字段存储在自己的集合中



我有两个集合,分别称为personsaddresses。其想法是让人员在字段address中保留一个地址。我使用SpringDataMongoDB来持久化那些提到的文档。

我通常制作";关系";人员之间>Address是存储地址的ID并将其提供给person对象。稍后,当我find()一个人时,我通过它的id解析地址对象,瞧,我有我的人+地址。

然而,我发现这有点麻烦,因为在我的代码中,我只想添加整个Address对象,而不仅仅是它的ID,这样我就可以在任何时候使用它,同时也可以将它保存到存储库中。

因此,我开始了一个小的单元测试,看看Spring Data MongoDB如何保存Address对象,如果它只是Person的一个字段,而不是由它自己的Repository保存的话。

这就是我想到的:

import org.springframework.data.mongodb.core.mapping.Document
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.stereotype.Repository
@Document("person")
data class Person(
val id: String,
val name: String,
val age: Int,
var address: Address
)
@Document("addresses")
data class Address(
val id: String,
val street: String?,
val number: Int?
)
@Repository
interface PersonRepository : MongoRepository<Person, String>
@Repository
interface AddressRepository : MongoRepository<Address, String>

这是单元测试——正如我所期望的那样,最后一步失败了:

internal class FooTest @Autowired constructor(
private val personRepository: PersonRepository,
private val addressRepository: AddressRepository
) {
@Test
fun `some experiment`() {
val testPerson = Person("001", "Peter", 25, Address("011","Lumberbumber", 12))
personRepository.save(testPerson)
val person = personRepository.findAll()[0]
assertThat(person).isNotNull
assertThat(person.address).isNotNull
assertThat(person.address.street).isEqualTo("Lumberbumber")
assertThat(person.address.number).isEqualTo(12)
// works because address was just copied into the object structure
// of `person` and was not seen as a standalone document
val address = addressRepository.findAll()[0]
assertThat(address.street).isEqualTo("Lumberbumber") // fails
assertThat(address.number).isEqualTo(12) // fails
// As expected `address` was not persisted alongside the `person` document.
}
}

因此,我考虑使用AbstractMongoEventListener<Person>来拦截保存过程,并从Person中选择Address对象,然后执行addressRepository.save(addressDocument),同时将一个轻量级地址对象(只有ID(放回Person文档中。当查找Person并再次将Person和Address组合在一起时,我也会采取相反的做法。

@Component
class MongoSaveInterceptor(
val addressRepository: AddressRepository
) : AbstractMongoEventListener<Person>() {
override fun onBeforeConvert(event: BeforeConvertEvent<Person>) {
val personToSave = event.source
val extractedAddress = personToSave.address
val idOfAddress = addressRepository.save(extractedAddress).id
personToSave.address = Address(idOfAddress, null, null)
}
override fun onAfterConvert(event: AfterConvertEvent<Person>) {
val person = event.source
val idOfAddress = person.address.id
val foundAddress = addressRepository.findById(idOfAddress)
foundAddress.ifPresent {
person.address = it
}
}
}

它是这样工作的,可能是我的需求的一个变通解决方案。

但是

我觉得一定有这样的东西已经在起作用了,我可能只需要找到合适的配置。

这就是我被困在自动取款机上的地方,需要一些指导。

另一项研究表明这是关于@DBRef的(https://www.baeldung.com/cascading-with-dbref-and-lifecycle-events-in-spring-data-mongodb)我必须使用。通过这种方式,SpringDataMongoDB存储嵌入的文档类,并在从数据库加载父文档对象时解析它。

相关内容

最新更新