注意
この記事の公開から時間が経っていたり、typeorm
のバージョンが異なる場合は、仕様が異なる場合があります。
動作確認: 2021/10/7
typeorm: v0.2.34
TL;DR
JOIN先の主キー(ID)で絞り込む場合
const teenProgrammers = await getRepository(User).find({
relations: ['role'], // なくてもOK
where: {
age: LessThanOrEqual(19),
role: {
id: programmer.id
}
}
})
JOIN先の主キー(ID)以外で絞り込む場合
const teenProgrammers = await getRepository(User).find({
join: {
alias: "user",
innerJoin: { role: "user.role" },
},
where: (qb: SelectQueryBuilder<User>) => {
qb.where({ age: LessThanOrEqual(19) }).andWhere(
"role.name = :roleName",
{ roleName: "programmer" }
);
},
});
前提条件
エンティティ
entity/role.ts
@Entity()
export class Role {
@PrimaryGeneratedColumn()
id?: number;
@Column()
name: string;
@OneToMany(() => User, user => user.id)
users: User[];
}
entity/user.ts
@Entity()
export class User {
@PrimaryGeneratedColumn()
id?: number;
@Column()
name: string;
@Column()
age: number;
@ManyToOne(() => Role)
role?: Role
}
メイン
index.ts
createConnection().then(async connection => {
const [programmer, boxer] = await getRepository(Role).save([
{
name: 'programmer'
},
{
name: 'boxer'
}
])
await getRepository(User).save([
{
name: 'alice',
age: 18,
role: programmer
},
{
name: 'bob',
age: 55,
role: boxer
},
{
name: 'carol',
age: 30,
role: programmer
}
])
})
}).catch(error => console.log(error))
データベース内の状態
role
id | name |
---|---|
1 | programmer |
2 | boxer |
user
id | name | age | roleId |
---|---|---|---|
1 | alice | 18 | 1 |
2 | bob | 55 | 2 |
3 | carol | 30 | 1 |
他の方法
クエリビルダを使う
表現力が高くSQLライクなのはいいですが、冗長です。
const teenProgrammers = await getRepository(User)
.createQueryBuilder("user")
.innerJoinAndSelect("user.role", "role")
.where("role.id = :roleId", { roleId: programmer.id })
.andWhere("age <= 19")
.getMany();
できない例
SQLも問題なく生成されますが、パラメータにnullが渡されてしまうのでダメです。
const teenProgrammers = await getRepository(User).find({
relations: ["role"],
where: {
age: LessThanOrEqual(19),
"role.id": programmer.id,
},
});
発行されるSQL(抜粋)
LEFT JOIN "role" "User__role"
ON "User__role"."id"="User"."roleId"
WHERE "User"."age" <= ?
AND "User"."roleId" = ?
-- PARAMETERS: [19,null]
ID以外をQBを使わずに指定するとダメ
この場合も発行されるSQLと渡されるパラメータは上記と同じでroleId = null
になります。
const teenProgrammers = await getRepository(User).find({
relations: ["role"],
where: {
age: LessThanOrEqual(19),
role: {
name: "programmer",
},
},
});
QBとrelationsを併用すると微妙
role.name
と指定することはできません。
const teenProgrammers = await getRepository(User).find({
relations: ["role"],
where: (qb: SelectQueryBuilder<User>) => {
qb.where({ age: LessThanOrEqual(19) }).andWhere(
"role.name = :roleName",
{ roleName: "programmer" }
);
},
});
FROM "user" "User"
LEFT JOIN "role" "User__role"
ON "User__role"."id"="User"."roleId"
WHERE "User"."age" <= ?
AND role.name = ? -- PARAMETERS: [19 "programmer"]
User__role.name
と書けば冒頭のコードと同様に動作しますが、内部的に自動生成された(されるはずの)文字列を指定するのは微妙な気がします。
const teenProgrammers = await getRepository(User).find({
relations: ["role"],
where: (qb: SelectQueryBuilder<User>) => {
qb.where({ age: LessThanOrEqual(19) }).andWhere(
"User__role.name = :roleName",
{ roleName: "programmer" }
);
},
});