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
"Cannot find matching entity for condition" when using upsertMany
with 5.8.6
#4786
Comments
Failing repro: import {
Collection,
Entity,
ManyToOne,
OneToMany,
OptionalProps,
PrimaryKey,
Property,
Unique,
} from '@mikro-orm/core';
import { MikroORM } from '@mikro-orm/sqlite';
@Entity({ abstract: true })
abstract class ApplicationEntity<Optionals = never> {
[OptionalProps]?: Optionals | 'createdAt' | 'updatedAt';
@PrimaryKey()
id!: number;
@Property({ name: 'created_at', defaultRaw: 'current_timestamp' })
createdAt!: Date;
@Property({ name: 'updated_at', defaultRaw: 'current_timestamp', onUpdate: () => new Date() })
updatedAt!: Date;
}
@Entity()
class InternalRole extends ApplicationEntity {
@Property()
name!: string;
@OneToMany(() => InternalRolePermission, permission => permission.internalRole, { orphanRemoval: true })
permissions = new Collection<InternalRolePermission>(this);
}
@Entity()
@Unique({ properties: ['subject', 'action', 'internalRole'] })
class InternalRolePermission extends ApplicationEntity {
@Property()
subject!: string;
@Property()
action!: string;
@ManyToOne(() => InternalRole, { onDelete: 'cascade' })
internalRole!: InternalRole;
}
let orm: MikroORM;
beforeAll(async () => {
orm = await MikroORM.init({
dbName: ':memory:',
entities: [InternalRole],
debug: true,
});
await orm.schema.refreshDatabase();
});
afterAll(async () => {
await orm.close(true);
});
test('4786', async () => {
const a = orm.em.create(InternalRole, { name: 'role' });
await orm.em.flush();
orm.em.clear();
let role = await orm.em.findOneOrFail(InternalRole, a);
await orm.em.upsertMany(InternalRolePermission, [
{ subject: 'User', action: 'read', internalRole: role },
{ action: 'update', subject: 'User', internalRole: role },
]);
orm.em.clear();
role = await orm.em.findOneOrFail(InternalRole, a);
await orm.em.upsertMany(InternalRolePermission, [
{ subject: 'User', action: 'read', internalRole: role },
{ action: 'update', subject: 'User', internalRole: role },
]);
}); |
Workaround is to provide the FK in your query: await orm.em.upsertMany(InternalRolePermission, [
{ subject: 'User', action: 'read', internalRole: role.id }, // using `role.id` instead of just `role`
{ action: 'update', subject: 'User', internalRole: role.id },
]); |
The Looks like when metadata is fetched at mikro-orm/packages/core/src/EntityManager.ts Line 780 in cbc0c50
comparableProps contains only columns from parent class. So getOnConflictReturningFields will not see the subject and name fields, and be unable to match data up with entities.
|
That's a wrong observation, as I said, the only issue to fix is the lookup of entities where you use a FK as part of a unique constraint. The returning statement won't contain all the properties, only those where we need the value. You provided values for both subject and name, there is no point in reloading those, as the point of upsert call is to make sure those are set to the values you provided. We only reload props without explicit value. |
OK, I have very little understanding of the library internals, just trying to step through the code and highlight what "feels wrong", given that observable difference is the read-back query that used to include upserted data fields, but no longer does. As for the workaround - yes, that works, thank you. |
I kinda doubt that as well, it never included the values you provide, as we already know the value. You can see how the queries changed in this snapshot: ab0ddee?w=1#diff-7b4e3cec759b75f447649d325800ca7180b41a5e3046c91c71c524b207dc1f96 |
I was referring to the read-back query - with 5.7.14 I was getting:
whereas 5.8.6 executes this for the same code:
It's possibly unrelated, maybe caused by some other change, but that's what originally stuck out to me. |
Hmm, that's indeed weird, but for a different reason - there should be no such query, everything is already returned via the returning statements of the upsert query (unless you use edit: nah I was wrong with that take, this particular example results in |
Describe the bug
A "Cannot find matching entity for condition" error gets raised when using
upsertMany
in 5.8.6, whereas same code works fine in 5.7.14. A what I assume a read-back query gets issued after insert statement, and that query differs between versions.Stack trace
5.7.14
5.8.6
To Reproduce
Expected behavior
Records get inserted without raising errors.
Additional context
NestJS 10.2 + Postgres 15.2
Versions
The text was updated successfully, but these errors were encountered: