Prisma数据模型:作为两个关系模型组合的主键



我在Prisma数据建模中遇到了一个问题,我有来约束用户只能为一个产品提交一次评审。我有以下针对非约束情况的设计

CustomerProduct应该组合成ProductReview模型中的主键,还是应该在应用程序服务器级别而不是数据库级别施加这种约束?

目前的数据模型(非约束版本):

type Product {
id: ID! @unique
title: String!
reviews: [ProductReview!]! @relation(name: "ProductReviews", onDelete: CASCADE)
}
type Customer {
id: ID! @unique
email: String @unique
}
type ProductReview {
id: ID! @unique
forProduct: Product! @relation(name: "ProductReviews", onDelete: SET_NULL)
byCustomer: Customer!
review: String!
ratinng: Float!
}

看起来Prisma v2引入了复合主键:

https://newreleases.io/project/github/prisma/prisma/release/2.0.0-preview023

这个链接的一个例子:

model User {
firstName String
lastName  String
email     String
@@id([firstName, lastName])
}

因此,在给定的问题示例中,应该可以添加到ProductReview:

@@id([id, forProduct])

我必须限制用户只能提交一份产品评论。我有以下针对非约束情况的设计。

不幸的是,Prisma目前无法做到这一点。已经有一个开放的功能请求要求此功能,请留下您的问题!

要在应用程序中获得该功能,您需要在应用程序层(例如express、apollo服务器或graphql-yoga)手动实现该约束。

您可以查看How to GraphQL的这一页,其中UserLinkVote类型也有类似的情况。以下是如何使用graphql-yoga:实现创建Vote并确保该用户没有投票的解析器

async function vote(parent, args, context, info) {
// 1
const userId = getUserId(context)
// 2
const linkExists = await context.db.exists.Vote({
user: { id: userId },
link: { id: args.linkId },
})
if (linkExists) {
throw new Error(`Already voted for link: ${args.linkId}`)
}
// 3
return context.db.mutation.createVote(
{
data: {
user: { connect: { id: userId } },
link: { connect: { id: args.linkId } },
},
},
info,
)
}

有一个解决方法。实现多个主键(如SQL)的概念。这个想法很简单,在"ProductReview"下再创建一个名为"UniqueCustomerReview"的字段。在突变时,将"UniqueCustomerReview"值设置为"[customerEmail]_[productID]"。所以我们现在可以使用prisma的默认唯一性。

您的数据模型将看起来像:

type Product {
id: ID! @unique
title: String!
reviews: [ProductReview!]! @relation(name: "ProductReviews", onDelete: CASCADE)
}
type Customer {
id: ID! @unique
email: String @unique
}
type ProductReview {
id: ID! @unique
forProduct: Product! @relation(name: "ProductReviews", onDelete: SET_NULL)
byCustomer: Customer!
review: String!
ratinng: Float!
UniqueCustomerReview:String!  # adding a extra field
}

创建或突变查询:

mutation{
createProductReview(
data:{
forProduct: {"connect":{"id":"<Replacec_with_product_id>"}}
byCustomer: {"connect":{"email":"<Replacec_with_customer_email>"}}
review: "my product review..."
ratinng: 5.0
UniqueCustomerReview:"loggedInUser@email.com_<Poductid>" # replace the string with user email and product id. this will create a unique product review for the user alone.
}
)
{
UniqueCustomerReview
# ... any requied fields
}
}

我将从MySQL的角度进行回答。如果你想强制要求给定的客户只能与给定的产品关联一次,那么你应该将(cusotmer_id, product_id)作为ProductReview表中的唯一密钥(可能是主密钥):

ALTER TABLE ProductReview ADD UNIQUE KEY uk_cust_prod (customer_id, product_id);

这意味着,当已经存在这样的关系时,任何为给定客户和产品插入记录的尝试都将在数据库级别失败。

如果您还想为此添加一个应用程序级别的检查,当然可以这样做,也许可以先在那里处理它。

在我的例子中,在id上进行字符串连接就足够了

因此CCD_ 12例如是"0";120-15〃;产品#120和客户#15

最新更新