Prisma数据模型:主键,是两个关系模型的组合

时间:2018-11-19 10:55:12

标签: mysql graphql 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!
}

4 个答案:

答案 0 :(得分:2)

  

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

不幸的是,Prisma目前无法做到这一点。已经有open feature request要求使用此功能,请放任您!

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

您可以看一下How to GraphQL的this页,其中的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,
  )
}

答案 1 :(得分:1)

我将从MySQL的角度回答。如果要强制给定客户只能与给定产品关联一次,则应在(cusotmer_id, product_id)表中将ProductReview设置为唯一键(可能是主键):

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

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

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

答案 2 :(得分:1)

有一种解决方法。实现多个主键(如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
}
        }

答案 3 :(得分:0)

就我而言,在 id 上进行字符串连接就足够了

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