diff --git a/src/driver/Driver.ts b/src/driver/Driver.ts index 3027e4afaf..70dc4c0ee5 100644 --- a/src/driver/Driver.ts +++ b/src/driver/Driver.ts @@ -175,7 +175,7 @@ export interface Driver { /** * Creates generated map of values generated or returned by database after INSERT query. */ - createGeneratedMap(metadata: EntityMetadata, insertResult: any): ObjectLiteral|undefined; + createGeneratedMap(metadata: EntityMetadata, insertResult: any, entityIndex?: number, entityNum?: number): ObjectLiteral|undefined; /** * Differentiate columns of this table and columns from the given column metadatas columns diff --git a/src/driver/mysql/MysqlDriver.ts b/src/driver/mysql/MysqlDriver.ts index d55a960ef4..d65b5d6a5f 100644 --- a/src/driver/mysql/MysqlDriver.ts +++ b/src/driver/mysql/MysqlDriver.ts @@ -709,11 +709,13 @@ export class MysqlDriver implements Driver { /** * Creates generated map of values generated or returned by database after INSERT query. */ - createGeneratedMap(metadata: EntityMetadata, insertResult: any) { + createGeneratedMap(metadata: EntityMetadata, insertResult: any, entityIndex: number) { const generatedMap = metadata.generatedColumns.reduce((map, generatedColumn) => { let value: any; if (generatedColumn.generationStrategy === "increment" && insertResult.insertId) { - value = insertResult.insertId; + // NOTE: When multiple rows is inserted by a single INSERT statement, + // `insertId` is the value generated for the first inserted row only. + value = insertResult.insertId + entityIndex; // } else if (generatedColumn.generationStrategy === "uuid") { // console.log("getting db value:", generatedColumn.databaseName); // value = generatedColumn.getEntityValue(uuidMap); diff --git a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts index 79fd5ef7f8..308f0c1a9f 100644 --- a/src/driver/sqlite-abstract/AbstractSqliteDriver.ts +++ b/src/driver/sqlite-abstract/AbstractSqliteDriver.ts @@ -526,11 +526,13 @@ export abstract class AbstractSqliteDriver implements Driver { /** * Creates generated map of values generated or returned by database after INSERT query. */ - createGeneratedMap(metadata: EntityMetadata, insertResult: any) { + createGeneratedMap(metadata: EntityMetadata, insertResult: any, entityIndex: number, entityNum: number) { const generatedMap = metadata.generatedColumns.reduce((map, generatedColumn) => { let value: any; if (generatedColumn.generationStrategy === "increment" && insertResult) { - value = insertResult; + // NOTE: When INSERT statement is successfully completed, the last inserted row ID is returned. + // see also: SqliteQueryRunner.query() + value = insertResult - entityNum + entityIndex + 1; // } else if (generatedColumn.generationStrategy === "uuid") { // value = insertValue[generatedColumn.databaseName]; } diff --git a/src/query-builder/ReturningResultsEntityUpdator.ts b/src/query-builder/ReturningResultsEntityUpdator.ts index 7dcd9f100d..c12e4794b5 100644 --- a/src/query-builder/ReturningResultsEntityUpdator.ts +++ b/src/query-builder/ReturningResultsEntityUpdator.ts @@ -93,7 +93,7 @@ export class ReturningResultsEntityUpdator { } // get all values generated by a database for us const result = Array.isArray(insertResult.raw) ? insertResult.raw[entityIndex] : insertResult.raw; - const generatedMap = this.queryRunner.connection.driver.createGeneratedMap(metadata, result) || {}; + const generatedMap = this.queryRunner.connection.driver.createGeneratedMap(metadata, result, entityIndex, entities.length) || {}; // if database does not support uuid generation we need to get uuid values // generated by orm and set them to the generatedMap diff --git a/test/github-issues/2131/entity/Post.ts b/test/github-issues/2131/entity/Post.ts new file mode 100644 index 0000000000..2004a60966 --- /dev/null +++ b/test/github-issues/2131/entity/Post.ts @@ -0,0 +1,12 @@ +import { PrimaryGeneratedColumn, Entity, Column } from "../../../../src"; + +@Entity() +export class Post { + + @PrimaryGeneratedColumn() + id: number | null; + + @Column() + title: string; + +} diff --git a/test/github-issues/2131/issue-2131.ts b/test/github-issues/2131/issue-2131.ts new file mode 100644 index 0000000000..6d67a4aaf8 --- /dev/null +++ b/test/github-issues/2131/issue-2131.ts @@ -0,0 +1,53 @@ +import "reflect-metadata"; +import { + closeTestingConnections, + createTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils"; +import { Connection } from "../../../src/connection/Connection"; +import { expect } from "chai"; +import { Post } from "./entity/Post"; + +describe("github issues > #2131 InsertResult return the same primary key", () => { + let connections: Connection[]; + const posts: Post[] = [{ + id: null, + title: "Post 1", + }, { + id: null, + title: "Post 2", + }, { + id: null, + title: "Post 3", + }, { + id: null, + title: "Post 4", + }]; + + before( + async () => + (connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + enabledDrivers: ["sqlite", "mysql"], + })) + ); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should get correct insert ids for multiple entities inserted", () => + Promise.all( + connections.map(async (connection) => { + await connection + .createQueryBuilder() + .insert() + .into(Post) + .values(posts) + .execute(); + + expect(posts[0].id).to.equal(1); + expect(posts[1].id).to.equal(2); + expect(posts[2].id).to.equal(3); + expect(posts[3].id).to.equal(4); + }) + )); +});