问题描述
1) 关于问题的情境化:
我正在尝试使用 03 个不同的服务/存储库(userService + postService + userRepo)在 03 个不同的 DB-Collections(Reactive MongoDB)中“删除”项目;
我的目标是使用相同的链接代码同时删除一个对象(在每个集合中);
下面是上述情况的代码:
1.1) 代码:
当前工作状态:未工作;
当前行为:不执行任何删除、delete-userService、delete-postService 或 delete-userRepo。
@Slf4j
@Service
@AllArgsConstructor
public class UserService implements UserServiceInt {
private final UserRepo userRepo;
private final PostServiceInt postServ;
private final CommentServiceInt comServ;
private final CustomExceptions customExceptions;
@Override
public Mono<Void> deleteInThreeCollections(String id) {
return userRepo
.findById(id)
.switchIfEmpty(customExceptions.userNotFoundException())
.map(user -> {
userRepo.delete(user); // First deletion - delete-method from userRepo
return user;
})
.flatMapMany(user -> postServ.findPostsByAuthorId(user.getId()))
.map(post -> {
postServ.delete(post); // Second deletion - delete-method from postService
return post;
})
.flatMap(post -> comServ.findCommentsByPostId(post.getPostId()))
.map(comServ::delete) // Third deletion - delete-method from commentService
.then()
;
}
}
2) 问题:
3) 更新:
找到解决方案
@Override
public Mono<Void> deleteInThreeCollections(String id) {
return userRepo
.findById(id)
.switchIfEmpty(customExceptions.userNotFoundException())
.flatMap(
user -> postServ
.findPostsByAuthorId(user.getId())
.flatMap(
post -> comServ.findCommentsByPostId(
post.getPostId())
.flatMap(comServ::delete)
.thenMany(
postServ.findPostsByAuthorId(
post.getAuthor()
.getId()))
.flatMap(postServ::delete)
)
.then(userRepo.delete(user))
);
}
非常感谢您的帮助
解决方法
假设您的 someclass.delete()
操作返回 Mono<Something>
。
主要问题是 map
不会订阅内部发布者。
这里必须使用 flatMap
/concatMap
... 操作,它们会订阅内部发布者(例如 xyz.delete)
如果您的删除方法没有返回已删除的项目,您可以使用 then(object)
以给定参数返回。
正如我所见,您不能同时执行所有删除操作,而是按顺序执行所有删除操作,因为每个操作的输入参数都是前一个操作的输出。如果您考虑批量处理所有帖子或评论......同时删除,那是可能的。您可以 collectList
id-s 并创建批处理操作 (deleteByIdIn(list of ids)
) 或创建并行通量并同时运行删除操作(批处理更好)。
这里我创建了一个带有虚假服务的最小示例来演示它:
import org.junit.jupiter.api.Test
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import reactor.test.StepVerifier
data class User(
val id: String
)
data class Post(
val id: String
)
data class Comment(
val id: String
)
class UserRepo {
fun finById(id: String): Mono<User> {
println("Find an user")
return Mono.just(User("1"))
}
//example if delete gives back the object
fun delete(user: User): Mono<User> {
println("delete $user")
return Mono.just(user)
}
}
class PostServiceInt {
fun findPostsByAuthorId(userId: String): Flux<Post> = Flux.fromIterable(listOf(Post("1"),Post("2")))
//and if not
fun delete(post: Post): Mono<Void> {
println("delete $post")
return Mono.empty()
}
}
class CommentServiceInt {
fun findCommentsByPostId(postId: String): Flux<Comment> = Flux.fromIterable(listOf(Comment("10"),Comment("7"),Comment("3"),Comment("4")))
fun delete(comment: Comment): Mono<Comment> {
println("delete $comment")
return Mono.just(comment)
}
}
class Example {
val userRepo = UserRepo()
val postServ = PostServiceInt()
val comServ = CommentServiceInt()
@Test
fun test() {
val result = userRepo.finById("1")
.switchIfEmpty(Mono.error { RuntimeException() })
.flatMap { user -> userRepo.delete(user) }
.flatMapMany { user -> postServ.findPostsByAuthorId(user.id) }
.flatMap { post -> postServ.delete(post).then(Mono.just(post)) }
.flatMap { post -> comServ.findCommentsByPostId(post.id) }
.flatMap { comment -> comServ.delete(comment) }
StepVerifier.create(result)
.expectNextCount(4)
.verifyComplete()
}
}