У меня проблема с моделированием данных Prisma, где у меня чтобы ограничить возможность отправки пользователем только одного отзыва о продукте.. У меня следующий дизайн для неограниченной ситуации.
Should
CustomerandProductbe combined into a primary key inProductReviewmodel, or should this constraint be imposed at the application server level, and not at the database level?
Модель данных на данный момент (версия без ограничений):
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!
}






Я отвечу с точки зрения MySQL. Если вы хотите, чтобы конкретный клиент мог быть связан с данным продуктом только один раз, вам следует сделать (cusotmer_id, product_id) уникальным ключом (возможно, первичным) в таблице ProductReview:
ALTER TABLE ProductReview ADD UNIQUE KEY uk_cust_prod (customer_id, product_id);
Это означает, что любая попытка вставить запись для данного покупателя и продукта, когда такая связь уже существует, не удастся на уровне базы данных.
Если вы также хотите добавить для этого проверку на уровне приложения, вы, конечно, можете это сделать и, возможно, сначала обработать это там.
I have to constrain that a user can submit only one review for a product. I have following design for the non-constrained situation.
К сожалению, в настоящее время это невозможно с Prisma. Уже существует открытый запрос функции, запрашивающий эту функцию, пожалуйста, оставьте ? по проблеме!
Чтобы получить эту функциональность в своем приложении, вам необходимо реализовать это ограничение вручную на уровне приложения (например, express, apollo-server или graphql-yoga).
Вы можете взглянуть на страницу это в How to GraphQL, где аналогичная ситуация наблюдается с типами User, Link и Vote. Вот как преобразователь для создания Vote и обеспечения отсутствия голосов от этого пользователя, который уже существует, реализован с помощью graphql-yoga:
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,
)
}
Привет, @nburk, поэтому сейчас идея состоит в том, чтобы решить эту проблему на уровне сервера приложений. Понятно! Вы также подняли запрос функции с тем же телом. Спасибо!
Есть обходной путь. Чтобы реализовать концепцию нескольких первичных ключей, таких как SQL. Идея проста: создайте еще одно поле под названием «UniqueCustomerReview» в «ProductReview». А при мутации установите значение «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:"[email protected]_<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
}
}
Вы должны добавить @unique к UniqueCustomerReview: String!
В моем случае достаточно было выполнить конкатенацию строк на id.
Таким образом, id - это, например, «120-15» для продукта №120 и клиента №15.
Спасибо @tim, поскольку Prisma не поддерживает это, проверка на уровне приложения кажется единственным способом. Не могли бы вы предложить «правильный способ» справиться с этим там?