具有嵌套 connectOrCreate 的 Prisma 多个创建查询抛出唯一约束失败
Posted
技术标签:
【中文标题】具有嵌套 connectOrCreate 的 Prisma 多个创建查询抛出唯一约束失败【英文标题】:Prisma multiple create queries with nested connectOrCreate throws unique constraint failed 【发布时间】:2021-10-05 07:31:53 【问题描述】:我正在尝试创建一个模型,其中电影和流派这两种类型之间存在多对多关系。
我从外部数据源异步检索电影列表,create
如果尚未创建,则每个都在我自己的数据库中,然后返回电影。
const retrieveList = async () =>
const results = await API.getMovies();
return results.map((item) => getMovieItem(item.id));
const getMovieItem = async (movieId) =>
// see if is already in database
const movie = await prisma.movie.findUnique(
where: tmdbId: movieId ,
);
if (movie)
return movie;
else
// create and return if doesn't exist
const details = await API.getDetails(movieId);
const genresData = details.genres.map((genre) => (
create:
name: genre.name,
,
where:
name: genre.name
,
));
return prisma.movie.create(
data:
title: details.title,
description: details.overview,
genres:
connectOrCreate: genresData,
,
,
select:
tmdbId: true,
id: true,
title: true,
description: true,
//...
,
);
;
问题在于似乎存在某种不一致,如果在某些运行中与外部 API 的连接速度足够慢,那么一切似乎都运行良好;但如果它足够快,它也会抛出错误:
Invalid `prisma.movie.create()` invocation:
Unique constraint failed on the fields: (`name`)"
可能是因为它试图创建一个已经创建的流派,而不是连接它。
【问题讨论】:
【参考方案1】:作为the docs states:
作为并发事务运行的多个
connectOrCreate
查询可能会导致竞争条件。 ...
因此,如果您同时请求 2 部相同类型的电影,但该类型尚不存在,则两个查询都会尝试创建该类型,只有第一个会成功。
Docs 建议捕获特定错误:
要解决这种情况,我们建议捕获唯一的违规异常(
PrismaClientKnownRequestError
,错误P2002
)并重试失败的查询。
您也可以先创建所有流派,例如:
// Some abstract function which extracts all the genres
const genres = gatherGenres(results);
await prisma.genres.createMany(
data: genres,
// Do nothing on duplicates
skipDuplicates: true,
);
然后创建所有电影并将它们连接到流派,因为流派已经创建。
另外,小 nitpick,你的函数 retrieveList
是不可等待的,因为它返回一个承诺数组,实际上要等到所有承诺完成,你需要在它上面使用 Promise.all
const retrieveList = async () =>
const results = await API.getMovies();
return results.map((item) => getMovieItem(item.id));
// ...
// You can just await it
await retrieveList()
// Need to use Promise.all
await Promise.all(retrieveList())
【讨论】:
感谢您的回答。因此,如果我要使用第二种方法,事先在数据库中收集所有可能的类型;您对在 apollo-server (graphql) 应用程序中执行查询的位置有什么建议吗? 我会这样做:从 api 获取所有电影,收集所有类型并创建它们,然后创建所有电影(并将它们连接到类型)。只需在retrieveList
函数中完成所有操作,请注意 await
以上是关于具有嵌套 connectOrCreate 的 Prisma 多个创建查询抛出唯一约束失败的主要内容,如果未能解决你的问题,请参考以下文章