Skip to content

Commit

Permalink
fix(core): fix extra updates when nullable embedded properties contai…
Browse files Browse the repository at this point in the history
…n FK

Closes #4788
  • Loading branch information
B4nan committed Oct 5, 2023
1 parent eae7e38 commit 77ffa4f
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/core/src/utils/EntityComparator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ export class EntityComparator {
return this.getGenericComparator(this.wrap(prop.name), cond);
}

return ` if (!equals(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})) diff${this.wrap(prop.name)} = current${this.wrap(prop.name)};`;
return this.getGenericComparator(this.wrap(prop.name), `!equals(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})`);
}

private wrap(key: string): string {
Expand Down
123 changes: 123 additions & 0 deletions tests/features/embeddables/GH4788.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import {
Embeddable,
Embedded,
Entity,
EventArgs,
EventSubscriber,
ManyToOne,
PrimaryKey,
PrimaryKeyProp,
PrimaryKeyType,
Property,
Ref,
} from '@mikro-orm/core';
import { MikroORM } from '@mikro-orm/sqlite';

@Embeddable()
class A {

@Property({ nullable: true })
alpha!: number | null;

@ManyToOne(() => C, { ref: true })
c!: Ref<C>;

}

@Entity()
class B {

@PrimaryKey()
id!: number;

@Embedded({ entity: () => A, object: false, nullable: true })
a!: A | null;

}

@Entity()
class C {

[PrimaryKeyType]!: number;
[PrimaryKeyProp]!: 'node';
@OneToOne({ entity: () => D, primary: true, onDelete: 'cascade', onUpdateIntegrity: 'cascade' })

Check failure on line 43 in tests/features/embeddables/GH4788.test.ts

View workflow job for this annotation

GitHub Actions / Build

Cannot find name 'OneToOne'.

Check failure on line 43 in tests/features/embeddables/GH4788.test.ts

View workflow job for this annotation

GitHub Actions / Lint

'OneToOne' is not defined
node!: Ref<D>;

}

@Entity()
class D {

@PrimaryKey()
id!: number;

}

@Embeddable()
class A2 {

@Property()
alpha!: number | null;

@ManyToOne(() => C2, { ref: true })
c2!: Ref<C2>;

}

@Entity()
class B2 {

@PrimaryKey()
id!: number;

@Embedded({ entity: () => A2, object: false, nullable: true })
a2!: A2 | null;

}

@Entity()
class C2 {

@PrimaryKey()
id!: number;

}

class FooBarSubscriber implements EventSubscriber {

async afterUpdate(args: EventArgs<any>): Promise<void> {
throw new Error('afterUpdate called but nothing changed');
}

}

let orm: MikroORM;

beforeAll(async () => {
orm = await MikroORM.init({
entities: [A, B, C, D, A2, B2, C2],
dbName: ':memory:',
subscribers: [new FooBarSubscriber()],
});
await orm.schema.createSchema();
});

afterAll(() => orm.close(true));

test('embedded with ManyToOne to foreign key as primary key entity', async () => {
orm.em.create(B, { a: null });
await orm.em.flush();
orm.em.clear();
await orm.em.getRepository(B).findAll();
await orm.em.flush(); // update query is created
orm.em.clear();
});

test('embedded with ManyToOne to entity', async () => {
orm.em.create(B2, { a2: null });
await orm.em.flush();
orm.em.clear();
await orm.em.getRepository(B2).findAll();
await orm.em.flush(); // no update query is created
orm.em.clear();
});

0 comments on commit 77ffa4f

Please sign in to comment.