From 30010f8f782f73fcd3c5be5746c3b1f65a4a419d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ad=C3=A1mek?= Date: Fri, 5 Jun 2020 08:19:39 +0200 Subject: [PATCH] fix(core): do not merge entity instances in `em.create()` Previously `em.create(Book, { tags: [t1, t2] })`, where t1 and t2 are entity instances, did automatically merge those in case they had PK set. This obviously don't work for composite keys, where we always know the PK. With this change, only PKs will be converted to references and merged, rest will be considered as new entities. cherry pick of fe204c678 --- lib/hydration/ObjectHydrator.ts | 21 ++++++++++++--------- lib/typings.ts | 2 +- tests/EntityManager.mongo.test.ts | 4 ++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/hydration/ObjectHydrator.ts b/lib/hydration/ObjectHydrator.ts index 2f935e93e6fd..9090b77823ab 100644 --- a/lib/hydration/ObjectHydrator.ts +++ b/lib/hydration/ObjectHydrator.ts @@ -1,6 +1,6 @@ import { AnyEntity, EntityData, EntityProperty, Primary } from '../typings'; import { Hydrator } from './Hydrator'; -import { Collection, EntityAssigner, ReferenceType, wrap } from '../entity'; +import { Collection, EntityAssigner, ReferenceType } from '../entity'; import { Utils } from '../utils'; export class ObjectHydrator extends Hydrator { @@ -75,18 +75,21 @@ export class ObjectHydrator extends Hydrator { } } - private createCollectionItem>(prop: EntityProperty, value: Primary | EntityData): T { - if (Utils.isPrimaryKey(value)) { - return this.factory.createReference(prop.type, value); - } + private createCollectionItem>(prop: EntityProperty, value: Primary | EntityData | T): T { + const meta = this.em.getMetadata().get(prop.type); + + if (Utils.isPrimaryKey(value, meta.compositePK)) { + const ref = this.factory.createReference(prop.type, value); + this.em.merge(ref); - const child = this.factory.create(prop.type, value as EntityData); + return ref; + } - if (wrap(child).__primaryKey) { - this.em.merge(child); + if (Utils.isEntity(value)) { + return value; } - return child; + return this.factory.create(prop.type, value as EntityData); } } diff --git a/lib/typings.ts b/lib/typings.ts index f4dcf196c3e8..503331c64568 100644 --- a/lib/typings.ts +++ b/lib/typings.ts @@ -94,7 +94,7 @@ export type MongoEntity = AnyEntity< export type EntityClass> = Function & { prototype: T }; export type EntityClassGroup> = { entity: EntityClass; schema: EntityMetadata | EntitySchema }; export type EntityName> = string | EntityClass; -export type EntityData> = { [K in keyof T]?: T[K] | Primary | CollectionItem[] } & Dictionary; +export type EntityData> = { [K in keyof T]?: T[K] | Primary | EntityData | CollectionItem[] } & Dictionary; export interface EntityProperty = any> { name: string & keyof T; diff --git a/tests/EntityManager.mongo.test.ts b/tests/EntityManager.mongo.test.ts index 9740f98f00ab..d0dff315102d 100644 --- a/tests/EntityManager.mongo.test.ts +++ b/tests/EntityManager.mongo.test.ts @@ -789,10 +789,10 @@ describe('EntityManagerMongo', () => { const cachedAuthor = orm.em.merge(Author, cache); expect(cachedAuthor).toBe(cachedAuthor.favouriteBook.author); expect(Object.keys(orm.em.getUnitOfWork().getIdentityMap())).toEqual([ - 'BookTag-' + tag1.id, - 'BookTag-' + tag3.id, 'Author-' + author.id, 'Book-' + book1.id, + 'BookTag-' + tag1.id, + 'BookTag-' + tag3.id, ]); expect(author).not.toBe(cachedAuthor); expect(author.id).toBe(cachedAuthor.id);