mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fix: prevent eager-loaded entities from overwriting manual relations (#11267)
Co-authored-by: Lucian Mocanu <alumni@users.noreply.github.com> Co-authored-by: Giorgio Boa <35845425+gioboa@users.noreply.github.com>
This commit is contained in:
parent
6e34756b9d
commit
2d8c5158db
@ -12,6 +12,7 @@ import { PropertyTypeFactory } from "./types/PropertyTypeInFunction"
|
||||
import { TypeORMError } from "../error"
|
||||
import { ObjectUtils } from "../util/ObjectUtils"
|
||||
import { InstanceChecker } from "../util/InstanceChecker"
|
||||
import { OrmUtils } from "../util/OrmUtils"
|
||||
|
||||
/**
|
||||
* Contains all information about some entity's relation.
|
||||
@ -520,7 +521,11 @@ export class RelationMetadata {
|
||||
entity,
|
||||
)
|
||||
} else {
|
||||
entity[propertyName] = value
|
||||
if (ObjectUtils.isObject(entity[propertyName])) {
|
||||
OrmUtils.mergeDeep(entity[propertyName], value)
|
||||
} else {
|
||||
entity[propertyName] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { expect } from "chai"
|
||||
import "reflect-metadata"
|
||||
import { DataSource } from "../../../../../src/data-source/DataSource"
|
||||
import {
|
||||
@ -5,11 +6,11 @@ import {
|
||||
createTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../../../utils/test-utils"
|
||||
import { User } from "./entity/User"
|
||||
import { Profile } from "./entity/Profile"
|
||||
import { Category } from "./entity/Category"
|
||||
import { Editor } from "./entity/Editor"
|
||||
import { Post } from "./entity/Post"
|
||||
import { Category } from "./entity/Category"
|
||||
import { Profile } from "./entity/Profile"
|
||||
import { User } from "./entity/User"
|
||||
|
||||
describe("relations > eager relations > basic", () => {
|
||||
let connections: DataSource[]
|
||||
@ -77,7 +78,7 @@ describe("relations > eager relations > basic", () => {
|
||||
loadedPost!.categories1.sort((a, b) => a.id - b.id)
|
||||
loadedPost!.categories2.sort((a, b) => a.id - b.id)
|
||||
|
||||
loadedPost!.should.be.eql({
|
||||
expect(loadedPost).to.deep.equal({
|
||||
id: 1,
|
||||
title: "about eager relations",
|
||||
categories1: [
|
||||
@ -104,6 +105,7 @@ describe("relations > eager relations > basic", () => {
|
||||
id: 1,
|
||||
firstName: "Timber",
|
||||
lastName: "Saw",
|
||||
deletedAt: null,
|
||||
profile: {
|
||||
id: 1,
|
||||
about: "I cut trees!",
|
||||
@ -117,6 +119,7 @@ describe("relations > eager relations > basic", () => {
|
||||
id: 1,
|
||||
firstName: "Timber",
|
||||
lastName: "Saw",
|
||||
deletedAt: null,
|
||||
profile: {
|
||||
id: 1,
|
||||
about: "I cut trees!",
|
||||
@ -138,10 +141,61 @@ describe("relations > eager relations > basic", () => {
|
||||
.where("post.id = :id", { id: 1 })
|
||||
.getOne()
|
||||
|
||||
loadedPost!.should.be.eql({
|
||||
expect(loadedPost).to.deep.equal({
|
||||
id: 1,
|
||||
title: "about eager relations",
|
||||
})
|
||||
}),
|
||||
))
|
||||
|
||||
it("should preserve manually requested nested relations with DeleteDateColumn", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
await prepareData(connection)
|
||||
|
||||
// Prepare test data - reusing existing entities
|
||||
const nestedProfile = new Profile()
|
||||
nestedProfile.about = "I am nested!"
|
||||
await connection.manager.save(nestedProfile)
|
||||
|
||||
const user = (await connection.manager.findOne(User, {
|
||||
where: { id: 1 },
|
||||
}))!
|
||||
user.nestedProfile = nestedProfile
|
||||
await connection.manager.save(user)
|
||||
|
||||
// Retrieve user with manually specified nested relation
|
||||
const retrievedEditor = await connection.manager.findOne(
|
||||
Editor,
|
||||
{
|
||||
where: { userId: 1 },
|
||||
relations: {
|
||||
user: {
|
||||
nestedProfile: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
// Assertions
|
||||
expect(retrievedEditor).to.deep.equal({
|
||||
userId: 1,
|
||||
postId: 1,
|
||||
user: {
|
||||
id: 1,
|
||||
firstName: "Timber",
|
||||
lastName: "Saw",
|
||||
deletedAt: null,
|
||||
nestedProfile: {
|
||||
id: 2,
|
||||
about: "I am nested!",
|
||||
},
|
||||
profile: {
|
||||
id: 1,
|
||||
about: "I cut trees!",
|
||||
},
|
||||
},
|
||||
})
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import { Entity } from "../../../../../../src/decorator/entity/Entity"
|
||||
import { PrimaryGeneratedColumn } from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn"
|
||||
import { Column } from "../../../../../../src/decorator/columns/Column"
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "../../../../../../src"
|
||||
|
||||
@Entity()
|
||||
export class Profile {
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
import { Entity } from "../../../../../../src/decorator/entity/Entity"
|
||||
import { PrimaryGeneratedColumn } from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn"
|
||||
import { Column } from "../../../../../../src/decorator/columns/Column"
|
||||
import { OneToOne } from "../../../../../../src/decorator/relations/OneToOne"
|
||||
import { JoinColumn } from "../../../../../../src/decorator/relations/JoinColumn"
|
||||
import {
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from "../../../../../../src"
|
||||
import { Profile } from "./Profile"
|
||||
|
||||
@Entity()
|
||||
@ -19,4 +23,10 @@ export class User {
|
||||
@OneToOne(() => Profile, { eager: true })
|
||||
@JoinColumn()
|
||||
profile: Profile
|
||||
|
||||
@DeleteDateColumn()
|
||||
deletedAt?: Date
|
||||
|
||||
@ManyToOne(() => Profile)
|
||||
nestedProfile: Profile
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user