question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Prisma is not joining tables when making a query with referentialIntegrity feature

See original GitHub issue

Bug description

Our database does not have foreign keys. To maintain relations, we’re using referentialIntegrity:

generator client {
  provider = "prisma-client-js"
  previewFeatures = ["referentialIntegrity"]
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
  referentialIntegrity = "prisma"
}

When calling prisma.foo.update, where foo has a relation with bridge table foo_bar. The problem is that prisma is not performing a join between foo and bar while trying to select data from both tables in one SELECT statement.

When I invoke this script:

  const updated = await prisma.merchant.update({
    where: { id: merchant.id },
    data: { currency: 'USD' },
  });

This are the queries logged by prisma:

BEGIN

SELECT 
  `my-local`.`merchant`.`id` 
FROM 
  `my-local`.`merchant` 
WHERE 
  `my-local`.`merchant`.`id` = ?

SELECT 
  `my-local`.`server`.`id`, 
  `my-local`.`server`.`merchant_id` 
FROM 
  `my-local`.`server` 
WHERE 
  (1=1 AND `my-local`.`server`.`merchant_id` IN (?))

SELECT 
  `my-local`.`refund_event`.`id`, 
  `my-local`.`refund_event`.`merchant_id` 
FROM 
  `my-local`.`refund_event` 
WHERE 
  (1=1 AND `my-local`.`refund_event`.`merchant_id` IN (?))

SELECT 
  `my-local`.`foo`.`id`, 
  `my-local`.`foo`.`merchant_id` 
FROM 
  `my-local`.`foo` 
WHERE 
  (1=1 AND `my-local`.`foo`.`merchant_id` IN (?))

SELECT 
  `my-local`.`foo`.`id`, 
  `my-local`.`foo_bar`.`foo_id`, 
  `my-local`.`foo_bar`.`bar_id` 
FROM 
  `my-local`.`foo_bar` 
WHERE 
  1=0

ROLLBACK

The error that follows is:

Invalid `prisma.merchant.update()` invocation in 
api/src/merchant/resolvers/mutation/toggleAcceptingOrders.ts:53:45 50 }); 
51 */ 52 → 53 const updated = await prisma.merchant.update( The column `my-local.foo.id` 
does not exist in the current database.

Specifically, the error is caused by

SELECT 
  `my-local`.`foo`.`id`, 
  `my-local`.`foo_bar`.`foo_id`, 
  `my-local`.`foo_bar`.`bar_id` 
FROM 
  `my-local`.`foo_bar`

A join is needed between foo and foo_bar.

The only thing I’ve found to work is to disable referentialIntegrity.

How to reproduce

With no foreign keys in your database, enable referentialIntegrity in your prisma schema:

generator client {
  provider = "prisma-client-js"
  previewFeatures = ["referentialIntegrity"]
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
  referentialIntegrity = "prisma"
}

Use a table (merchant) such that it has a one-to-many relationship with table foo and table foo has a relation to a bridge table foo_bar.

Then, call a prisma.merchant.update() and watch the Invalid prisma.merchant.update() invocation error occur following the same pattern as described above.

Expected behavior

No response

Prisma schema (roughly)

model Merchant {
  id               Int      @id @default(autoincrement()) @db.UnsignedInt

  bars             Bar[]
  foos          Foo[]

  @@map("merchant")
}
model Foo {
  id         Int     @id @default(autoincrement()) @db.UnsignedInt

  merchant     Merchant      @relation(fields: [merchantId], references: [id])
  merchantId   Int           @map("merchant_id") @db.UnsignedInt
  fooBars FooBar[]

  @@map("foo")
}
model FooBar {
  bar      Bar    @relation(fields: [barId], references: [id])
  barId    Int     @map("barId") @db.UnsignedInt
  foo   Foo @relation(fields: [fooId], references: [id])
  fooId Int     @map("foo_id") @db.UnsignedInt

  @@id([fooId, barId])
  @@index([barId], map: "bar_id")
  @@map("foo_bar")
}
model Bar {
  id          Int       @id @default(autoincrement()) @db.UnsignedInt

  merchant       Merchant       @relation(fields: [merchantId], references: [id])
  merchantId     Int            @map("merchant_id") @db.UnsignedInt
  fooBars   FooBar[]

  @@map("bar")
}

Environment & setup

  • OS: Mac OS 12.2.1
  • Database: MySQL 8.0.28
  • Node.js version: 16.14.2

Prisma Version

3.9.1

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:1
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
matthewninjacommented, Apr 13, 2022

Thanks for the quick response! Yes, let’s close this as a duplicate.

1reaction
janpiocommented, Apr 13, 2022

I expanded that other issue’s title, and posted a comment: https://github.com/prisma/prisma/issues/10758#issuecomment-1098430578

If you agree with all this, we can close this issue here as a duplicate I think. Thanks for the great report and iteration on it.

Read more comments on GitHub >

github_iconTop Results From Across the Web

SQL joins without relations/foreign keys/raw query #13517
Problem. I sometimes find myself wanting to join 2 tables that are related by a column, but don't have referential integrity.
Read more >
Referential actions - Prisma
Referential actions are features of foreign key constraints that exist to preserve referential integrity in your database. When you define relationships ...
Read more >
Manage relations between records with relation modes in ...
The prisma relation mode emulates some foreign key constraints and referential actions for each Prisma Client query to maintain referential integrity, using ...
Read more >
Troubleshooting relations - Prisma
Solution. You need to use explicit relation syntax, manually create the join model, and verify that this join model has a primary key....
Read more >
Using Prisma with PlanetScale
Referential actions and integrity. To support scaling across multiple database servers, PlanetScale does not allow the use of foreign key constraints, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found