我在Prisma数据建模中遇到了一个问题,我有来约束用户只能为一个产品提交一次评审。我有以下针对非约束情况的设计。
Customer
和Product
应该组合成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的这一页,其中User
、Link
和Vote
类型也有类似的情况。以下是如何使用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