New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: better support of one-to-one and many-to-one relation-based properties in where clauses #7805
fix: better support of one-to-one and many-to-one relation-based properties in where clauses #7805
Conversation
2e62c78
to
261c7cc
Compare
053de61
to
d2fb304
Compare
I guess documentation needs to be updated as well.. EDIT: Just a little bit. Really, documentation should be rewritten in some areas.. |
Also this sort of continues a bit of an anti-pattern. It applies to the where clause directly in the case of We probably want to instead do existence checks to confirm the primary entity we're querying HAS the relations that match the where clause rather than the way we're doing it now. However, that really breaks the assumptions users might have over how the query works.. Well, right now they assume it just doesn't work at all. |
d2fb304
to
5333414
Compare
b982f0e
to
08783d7
Compare
08783d7
to
5866560
Compare
This is big. Thanks.
|
a7b3d24
to
640ae29
Compare
640ae29
to
84bb17a
Compare
Is there any timeline for when these changes will published in a new version of typeorm? |
This feature is a must, please release it soon enough. |
Hello, is this feature already relased? |
when is this getting released ? |
It is already relased in 0.2.35 @ |
If I have a *-to-many relationship, how do I do it? following doesn't work:
|
True, one-to-many fails sadly... |
also I have this case @Entity()
class Record {
@OneToOne(() => Report, { nullable: false })
@JoinColumn({ name: 'entry_report_id' })
entryReport: Report;
}
@Entity()
class Report {
@ManyToOne(() => Record)
record: Record;
@ManyToOne(() => User)
pacient: User;
}
// and then, build query like this
return this.recordRepository.find({
where: {
entryReport: {
pacient: { id: id }
}
}
}); |
I'm trying to understand why the restriction for one-to-many exists. Is the assumption that WHERE should always filter the primary entity instead of the relation entity? In my case I would like filter the relation entity by a nested WHERE. |
Yes exactly, James explained this here / see previous comments over there. You most likely want a subquery for *toMany where clauses, and this is currently only possible manually using QueryBuilder |
I see. Thanks for clarifying. It's a bit unfortunate you cannot do it, even if you are aware of the limitations. |
@phil294 could you show an example? |
@giovanni-orciuolo check this comment and maybe also the entire thread. In short, there's currently two ways to do this with TypeORM (if I didn't miss any recent advancements regarding this): SELECT * FROM addresses a
JOIN contacts c ON c.address_id = a.id
WHERE a.city = 'Colorado'
AND c.name = 'John'; getRepository(Address).createQueryBuilder("a")
.leftJoinAndSelect("a.contacts", "c")
.where("a.city = :city", { city: 'Colorado' })
.andWhere("c.name = :name", { name: 'John' })
.getMany() SELECT * FROM addresses a
JOIN contacts c ON c.address_id = a.id
WHERE a.id IN (
SELECT a1.id FROM addresses a1
JOIN contacts c1 ON c1.address_id = a1.id
WHERE a1.city = 'Colorado'
AND c1.name = 'John'
) getRepository(Address).createQueryBuilder("a")
.leftJoinAndSelect("a.contacts", "c")
.where(qb => {
const sub_query = qb.subQuery()
.select("a1.id")
.from(Address, "a1")
.leftJoinAndSelect("a1.contacts", "c1")
.where("a1.city = :city", { city: 'Colorado' })
.andWhere("c1.name = :name", { name: 'John' })
.getQuery()
return "a.id IN " + sub_query
})
.getMany() It's important to understand the difference between those two, as they return two different things: The first only ever one contact per address (John), the second one all contacts of each address. I haven't manually tested those queries but in principle they should work, I'm using them myself in different contexts all the time. Because it's not entirely clear which of these two versions should be the default, TypeORM does not offer to do this for you with find options, that's why relation-based find queries aren't supported for *toMany right now (see the linked issue for more details) |
@phil294 thank you so much for the examples, they are very clear. However, I do not understand the part where you concatenate |
@giovanni-orciuolo did you forget to |
Thank you for the response, I forgot to update my comment. Indeed I forgot the |
Description of change
updates the
QueryBuilder
to support buildingWHERE
clauses viaObjectLiteral
s that go across relations.Most of this was done to migrate the
whereInIDs
over to using native QueryBuilder features, and abstract the query compilation away from theQueryBuilder
interface.for example
This also applies to
FindOptions
Fixes #1847
Fixes #2707
Fixes #7251
Fixes #4906
Fixes #6264
Fixes #4837
Fixes #4787
Fixes #5323
Fixes #7583
Pull-Request Checklist
master
branchnpm run lint
passes with this changenpm run test
passes with this changeFixes #0000