Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: ManyToMany ER_DUP_ENTRY error (#10343)
* fix: ensure comparing EntityMapIds in `buildForSubjectRelation` I have found the issue (for me at least). In the method `buildForSubjectRelation` of `ManyToManySubjectBuilder`, in order to know if it is needed to insert the relation rows `databaseRelatedEntityIds` is compared with `relatedEntityRelationIdMap` (line 154). The problem is that `databaseRelatedEntityIds` is not always an "EntityIdMap". If one is overloading the entity in the `afterLoad` event of an EventSubscriber for example the line 102 : `const databaseRelatedEntityValue = relation.getEntityValue(subject.databaseEntity);` will return an "enhanced" object with additional properties. To fix this, in this commit, we ensure that `databaseRelatedEntityIds` is containing an "EntityIdMap". Closes #5704 * refactor: describe.only -> describe removes describe.only. * style: npm run format format code. * Update issue-5704.ts refactor: typo on post title --------- Co-authored-by: blemoine <services+bitbucket@blemoine.pro>
- Loading branch information
Showing
5 changed files
with
132 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { | ||
Column, | ||
ManyToMany, | ||
Entity, | ||
PrimaryGeneratedColumn, | ||
} from "../../../../src" | ||
import { Post } from "./Post" | ||
|
||
@Entity() | ||
export class Category { | ||
@PrimaryGeneratedColumn() | ||
id: number | ||
|
||
@Column() | ||
name: string | ||
|
||
@ManyToMany(() => Post, (o) => o.categories) | ||
posts!: Promise<Post[]> | ||
|
||
addedProp: boolean = false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { | ||
Column, | ||
Entity, | ||
JoinTable, | ||
ManyToMany, | ||
PrimaryGeneratedColumn, | ||
} from "../../../../src" | ||
import { Category } from "./Category" | ||
|
||
@Entity() | ||
export class Post { | ||
@PrimaryGeneratedColumn() | ||
id: number | ||
|
||
@Column() | ||
title: string | ||
|
||
@ManyToMany(() => Category, (o) => o.posts, { | ||
cascade: true, | ||
}) | ||
@JoinTable() | ||
categories!: Promise<Category[]> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import "reflect-metadata" | ||
import { | ||
closeTestingConnections, | ||
createTestingConnections, | ||
reloadTestingDatabases, | ||
} from "../../utils/test-utils" | ||
import { DataSource } from "../../../src" | ||
import { Post } from "./entity/Post" | ||
import { Category } from "./entity/Category" | ||
import { assert } from "chai" | ||
|
||
describe("github issues > #5704 Many-to-many gives error ER_DUP_ENTRY everytime I save. This one also related to inverseJoinColumn.", () => { | ||
let connections: DataSource[] | ||
before( | ||
async () => | ||
(connections = await createTestingConnections({ | ||
entities: [__dirname + "/entity/*{.js,.ts}"], | ||
subscribers: [__dirname + "/subscriber/*{.js,.ts}"], | ||
enabledDrivers: ["mysql"], | ||
})), | ||
) | ||
beforeEach(() => reloadTestingDatabases(connections)) | ||
after(() => closeTestingConnections(connections)) | ||
|
||
it("should work as expected", () => | ||
Promise.all( | ||
connections.map(async (connection) => { | ||
const postName = "post for issue #5704" | ||
const catName = "cat for issue #5704" | ||
|
||
let post1 = await connection.manager.findOne(Post, { | ||
where: { title: postName }, | ||
}) | ||
|
||
let category1 = await connection.manager.findOne(Category, { | ||
where: { name: catName }, | ||
}) | ||
|
||
if (!category1) { | ||
category1 = new Category() | ||
category1.name = catName | ||
await connection.manager.save(category1) | ||
} | ||
|
||
if (!post1) { | ||
post1 = new Post() | ||
post1.title = postName | ||
post1.categories = Promise.resolve([category1]) | ||
await connection.manager.save(post1) | ||
} | ||
|
||
const categoryTest = await connection.manager.findOne( | ||
Category, | ||
{ | ||
where: { name: catName }, | ||
}, | ||
) | ||
assert.isTrue(categoryTest instanceof Category) | ||
|
||
post1.categories = Promise.resolve([categoryTest as Category]) | ||
|
||
// This is the line that causes the error "QueryFailedError: ER_DUP_ENTRY: Duplicate entry '1-1' for key 'PRIMARY'" with previous code | ||
await connection.manager.save(post1) | ||
}), | ||
)) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Category } from "../entity/Category" | ||
import { EntitySubscriberInterface, EventSubscriber } from "../../../../src" | ||
|
||
@EventSubscriber() | ||
export class CategorySubscriber implements EntitySubscriberInterface<Category> { | ||
listenTo() { | ||
return Category | ||
} | ||
|
||
async afterLoad(entity: Category): Promise<any> { | ||
entity.addedProp = true | ||
} | ||
} |