Prisma Datamodel: первичный ключ как комбинация двух реляционных моделей

У меня проблема с моделированием данных Prisma, где у меня чтобы ограничить возможность отправки пользователем только одного отзыва о продукте.. У меня следующий дизайн для неограниченной ситуации.

Should Customer and Product be combined into a primary key in ProductReview model, 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!
}
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
5
0
3 536
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Я отвечу с точки зрения MySQL. Если вы хотите, чтобы конкретный клиент мог быть связан с данным продуктом только один раз, вам следует сделать (cusotmer_id, product_id) уникальным ключом (возможно, первичным) в таблице ProductReview:

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

Это означает, что любая попытка вставить запись для данного покупателя и продукта, когда такая связь уже существует, не удастся на уровне базы данных.

Если вы также хотите добавить для этого проверку на уровне приложения, вы, конечно, можете это сделать и, возможно, сначала обработать это там.

Спасибо @tim, поскольку Prisma не поддерживает это, проверка на уровне приложения кажется единственным способом. Не могли бы вы предложить «правильный способ» справиться с этим там?

devautor 19.11.2018 13:48
Ответ принят как подходящий

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, поэтому сейчас идея состоит в том, чтобы решить эту проблему на уровне сервера приложений. Понятно! Вы также подняли запрос функции с тем же телом. Спасибо!

devautor 19.11.2018 14:05

Есть обходной путь. Чтобы реализовать концепцию нескольких первичных ключей, таких как 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!

Jeremy Bernier 16.12.2019 16:56

В моем случае достаточно было выполнить конкатенацию строк на id.

Таким образом, id - это, например, «120-15» для продукта №120 и клиента №15.

Другие вопросы по теме