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.

JoinColumn takes only first foreign key into account when passing an array as parameter

See original GitHub issue

Issue type:

[ ] question [x] bug report [ ] feature request [ ] documentation issue

Database system/driver:

[ ] cordova [ ] mongodb [ ] mssql [x] mysql / mariadb [ ] oracle [ ] postgres [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

TypeORM version:

[ ] latest [ ] @next [x] 0.2.7

Steps to reproduce or a small repository showing the problem:

Let’s imagine situation that Photo row in database has two foreign keys which reference to Author row in database. In that case we want to do query where we left join on both foreign keys. Below you can see the models where I pass array of foreign keys to JoinColumn. Also according to the documentation JoinColumn should accept arrays.

// Author.ts
import { OneToMany } from 'typeorm';

export class Author {
  @OneToMany(type => Photo, photo => photo.author)
  photos!: Photo[];
}

// Photo.ts
import { ManyToOne, JoinColumn } from 'typeorm';

export class Photo {
  @ManyToOne(type => Author, author => author.photos)
  @JoinColumn([{ name: 'from_id' }, { name: 'to_id' }])
  author!: Author;
}

But when I do query like this:

this.authorRepository
  .createQueryBuilder('author')
  .leftJoinAndSelect('author.photos', 'photo')
  .where('author.id = :id', { id: 123 })
  .orderBy({
    'author.last_photo_time': 'DESC',
    'photo.created': 'DESC',
  })
  .printSql()
  .getMany();

it produces wrong query

SELECT
    `author`.`id` AS `author_id`,
    `author`.`created` AS `author_created`,
    `author`.`updated` AS `author_updated`,
    `author`.`last_photo_time` AS `author_last_photo_time`,
    `author`.`last_photo` AS `author_last_photo`,
    `author`.`last_photo_from_id` AS `author_last_photo_from_id`,
    `photo`.`mid` AS `photo_mid`,
    `photo`.`from_id` AS `photo_from_id`,
    `photo`.`to_id` AS `photo_to_id`,
    `photo`.`from_id` AS `photo_from_id`,
    `photo`.`to_id` AS `photo_to_id`,
    `photo`.`photo` AS `photo_photo`,
    `photo`.`created` AS `photo_created`
FROM
    `author` `author`
        LEFT JOIN
    `photo` `photo` ON `photo`.`from_id` = `author`.`id` // here should be also `photo`.`to_id` = `author`.`id`
WHERE
    `author`.`id` = 123
ORDER BY `author`.`last_photo_time` DESC , `photo`.`created` DESC

As you can see from the query LEFT JOIN is missing the second join on the to_id foreign key.

So looks like JoinColumn take into account only the first object in the array because if I put to_id as first array item then to_id was in the produces query.

So the here is wrong behaviour: LEFT JOIN photo ON photo.from_id = author.id

Here would be correct behaviour when this bug is fixed: LEFT JOIN photo ON photo.from_id = author.id OR photo.to_id = author.id

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

4reactions
henrikracommented, Oct 28, 2018

I don’t know the codebase at all so I have created here entity definition which can be reused.

import { Entity, PrimaryGeneratedColumn, OneToMany, Column } from 'typeorm';
import { Photo } from './Photo';

@Entity('db_author')
export class Author {
  @PrimaryGeneratedColumn()
  cid!: number;

  @Column({ nullable: true })
  last_photo_time!: Date;

  @OneToMany(type => Photo, photo => photo.author)
  photos!: Photo[];
}
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
import { Author } from './Author';

@Entity('db_photo')
export class Photo {
  @PrimaryGeneratedColumn()
  mid!: number;

  @Column()
  from_cid!: number;

  @Column()
  to_cid!: number;

  @Column({ nullable: true })
  created!: Date;

  @ManyToOne(type => Author, author => author.photos)
  @JoinColumn([{ name: 'from_cid' }, { name: 'to_cid' }])
  author!: Author;
}

Basically db_photo has TWO foreign keys from_cid and to_cid which point to the primary key cid on db_author.

And when creating query like this

this.authorRepository
  .createQueryBuilder('author')
  .leftJoinAndSelect('author.photos', 'photo')
  .where('author.cid = :cid', { cid: 123 })
  .orderBy({
    'author.last_photo_time': 'DESC',
    'photo.created': 'DESC',
  })
  .printSql()
  .getMany();

I get this query:

SELECT
    `author`.`cid` AS `author_cid`,
    `author`.`last_photo_time` AS `author_last_photo_time`,
    `photo`.`mid` AS `photo_mid`,
    `photo`.`from_cid` AS `photo_from_id`,
    `photo`.`to_cid` AS `photo_to_id`,
    `photo`.`created` AS `photo_created`
FROM
    `author` `author`
        LEFT JOIN
    `photo` `photo` ON `photo`.`from_cid` = `author`.`cid`
WHERE
    `author`.`cid` = 123
ORDER BY `author`.`last_photo_time` DESC , `photo`.`created` DESC

But instead I though it would be like this because I passed array to JoinColumn

SELECT
    `author`.`cid` AS `author_cid`,
    `author`.`last_photo_time` AS `author_last_photo_time`,
    `photo`.`mid` AS `photo_mid`,
    `photo`.`from_cid` AS `photo_from_id`,
    `photo`.`to_cid` AS `photo_to_id`,
    `photo`.`created` AS `photo_created`
FROM
    `author` `author`
        LEFT JOIN
    `photo` `photo` ON `photo`.`from_cid` = `author`.`cid` OR `photo`.`to_cid` = `author`.`cid`
WHERE
    `author`.`cid` = 123
ORDER BY `author`.`last_photo_time` DESC , `photo`.`created` DESC

Is this more helpful for you @Kononnable ? 😃

0reactions
henrikracommented, Dec 3, 2018

We just did custom query because this is such a edge case

Read more comments on GitHub >

github_iconTop Results From Across the Web

what is @JoinColumn and how it is used in Hibernate
This statement: "Since you have made @JoinColumn associated with Patient class object, that's why foreign key is created on Patient table." is ...
Read more >
@JoinColumn Annotation Explained | Baeldung
The name of the foreign key column in the Office entity is specified by name property.
Read more >
Configuring how Relationship Joins
relationship() looks to this foreign key status as it decides how it should load and persist data for this relationship. However, the relationship.primaryjoin ......
Read more >
Chapter 2. Mapping Entities - Red Hat on GitHub
A Customer is linked to a Passport , with a foreign key column named passport_fk in the Customer table. The join column is...
Read more >
A Guide to JPA with Hibernate (Relationship Mappings)
The first parameter, joinColumns defines how to configure the join column (foreign key) of the owning side of the relationship in the table....
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