5

我在 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!
}
4

5 回答 5

2

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

您的数据模型将如下所示:

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
}
        }
于 2019-07-11T08:36:55.043 回答
2

我必须限制用户只能为产品提交一条评论。对于不受约束的情况,我有以下设计。

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

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

您可以查看 How to GraphQL 的这个页面,其中User,LinkVote类型有类似的情况。以下是使用 graphql-yoga 实现创建 aVote并确保不存在该用户投票的解析器的方法:

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,
  )
}
于 2018-11-19T11:15:06.367 回答
1

我将从MySQL的角度回答。如果您想强制给定客户只能与给定产品关联一次,那么您应该(cusotmer_id, product_id)在表中创建一个唯一键(可能是主键)ProductReview

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

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

如果您还想为此添加应用程序级别检查,您当然可以这样做,并且可能首先在那里处理它。

于 2018-11-19T11:00:59.233 回答
1

It looks like Prisma v2 introduced composite primary keys:

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

An example from that link:

model User {
  firstName String
  lastName  String
  email     String

  @@id([firstName, lastName])
}

So in the given question example, it should be possible to add to ProductReview:

@@id([id, forProduct])
于 2022-01-30T05:07:22.427 回答
0

就我而言,在id

因此id,例如产品#120 和客户#15 的“120-15”

于 2021-06-28T21:49:10.620 回答