1

作为 R2DBC 学习过程的一部分,我有一个复杂的场景,即创建相关实体作为创建主要实体的一部分。我正在尝试创建一个电影实体及其相关实体。 在此处输入图像描述

我的要求是这样的

{
"title" : "Star Wars: The Rise Of Skywalker",
"description": "In the riveting conclusion of the landmark Skywalker saga, new legends will be born-and the final battle for freedom is yet to come.",
"releaseYear": "2019",
"language": "English",
"rentalDuration": 7,
"rentalRate": "4.99",
"length": 165,
"replacementCost": "14.99",
"rating": "PG",
"specialFeaturesList": [ "SciFi", "Star Wars"],
"filmCategory": "Sci-Fi",
"actors":[
    {
        "firstName":"Daisy",
        "lastName": "Ridley"
    },
    {
        "firstName":"Carrie",
        "lastName":"Fisher"
    },
    {
        "firstName": "Oscar",
        "lastName": "Isaac"
    },
    {
         "firstName": "Adam",
        "lastName": "Driver"
    },
    {
          "firstName": "Mark",
        "lastName": "Hamill"
    },
    {
          "firstName": "John",
        "lastName": "Boyega"
    }
]

}

下面是我的逻辑和代码

   /**
 * Logic :
 * Transaction start
 * -- find Language or insert
 * -- find Flim by (Title,release year and languageId) or insert
 * -- foreach( actor)
 * ---- find or create actor
 * ---- find or create film_actor ( film id, actor)
 * -- end
 * -- for category
 * ---- find category or insert
 * ---- find film_category or insert
 * -- end
 * -- Map data
 * Transaction end
 *
 * @param filmRequest
 * @return Mono<Pair < Boolean, FilmModel>>
 */

代码 :

@Override
public Mono<Pair<Boolean, FilmModel>> create(FilmRequest filmRequest) {

    return Mono.just(filmRequest)
            .flatMap(this::getOrCreateLanguage)
            .flatMap(languageInput -> getOrCreateFilm(filmRequest, languageInput.getLanguageId()))
            .flatMap(filmInput ->
                    Mono.zip(Mono.just(filmInput),
                            Flux.fromIterable(filmRequest.getActors())
                                    .flatMap(this::getOrCreateActor)
                                    .doOnNext(actorInput -> getOrCreateFilmActor(filmInput.getSecond().getFilmId(), actorInput.getActorId()))
                                    .collectList(),
                            Mono.just(filmRequest.getFilmCategory())
                                    .flatMap(this::getOrCreateCategory)
                                    .flatMap(category -> getOrCreateFilmCategory(filmInput.getSecond().getFilmId(), category.getCategoryId()))
                    ))
            .map(tuple -> {
                FilmModel filmModel = GenericMapper.INSTANCE.filmToFilmModel(tuple.getT1().getSecond());
                List<ActorModel> actorModelList = tuple.getT2().stream().map(GenericMapper.INSTANCE::actorToActorModel).collect(Collectors.toList());
                filmModel.setActors(actorModelList);
                return Pair.of(tuple.getT1().getFirst(), filmModel);
            }).as(operator::transactional);
}

这是我得到的失败:

TransientDataAccessResourceException:无法更新表 [film_category]。Id [1006] 的行不存在。

https://gist.github.com/harryalto/d91e653ca1054038b766169142737f87

电影实体 ID 未保留,因此依赖插入失败。

4

1 回答 1

0

我解决了这个问题。主要问题是对于film_category 和film_actor,主要是外键的组合(即film_id 来自film,category_id 来自category/actor_id 来自actor)。我不得不为类似这样的东西更改存储库的定义

@Repository
public interface FilmActorRepository extends 
ReactiveCrudRepository<FilmActor, FilmActorPK> {

    @Query("select * from film_actor  where film_id = :film_id")
    Flux<FilmActor> findAllByFilmId(@Param("film_id") final Long filmId);

    @Query("select * from film_actor  where film_id = :film_id and actor_id = :actor_id limit 1")
    Mono<FilmActor> findByFilmIdAndActorId(@Param("film_id") final Long filmId, @Param("actor_id") final Long actorId);

    @Modifying
    @Query("insert into film_actor (film_id, actor_id, last_update) values (:#{#filmActor.filmId}, :#{#filmActor.actorId}, now()) on conflict DO NOTHING")
    Mono<FilmActor> save(final FilmActor filmActor);
}

其中 FilmActorPK 定义为

@Value
@Builder
public class FilmActorPK implements Serializable {
    private long filmId;
    private long actorId;
}

我为 FilmCategoryRepository 做了类似的练习

@Repository
public interface FilmCategoryRepository extends 
ReactiveCrudRepository<FilmCategory, FilmCategoryPK> {

    @Query("select * from film_category  where category_id = :category_id and film_id = :film_id limit 1")
    Mono<FilmCategory> findFirstByCategoryIdAndFilmId(@Param("category_id") Long categoryId, @Param("film_id") Long filmId);

    @Query("select * from film_category   where   film_id = :film_id limit 1")
    Mono<FilmCategory> findFirstByFilmId(@Param("film_id") Long filmId);

    @Modifying
    @Query(
        "insert into film_category (film_id, category_id, last_update) 
       values (:#{#filmCategory.filmId}, :#{#filmCategory.categoryId}, 
       now()) on conflict DO NOTHING"
    )
    Mono<FilmCategory> save(final FilmCategory filmCategory);
}

其中 FilmCategoryPK 定义为

@Value
@Builder
public class FilmCategoryPK implements Serializable {
    private long filmId;
    private long categoryId;
}

这个想法来自这个问题here

这解决了我的问题。我知道 R2DBC 有不同的理念,并且可以在 R2DBC 中完成一些事情,以使其与 JPA 的语法类似,而有些事情则不能。但我真的很喜欢 R2DBC,因为我在学习过程中会做更多的练习。

于 2021-12-27T23:18:12.823 回答