question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unexpected Load event triggered on subscriber when inserting versioned entity

See original GitHub issue

If we implement a simple subscriber that track down entities lifecycle by logging out events on the console:

@EventSubscriber()
export class EntitySubscriber implements EntitySubscriberInterface {
    public afterLoad(entity: any) {
        console.log(`AFTER LOAD -> ${JSON.stringify(entity)}`);
    }
    beforeInsert(event: InsertEvent<any>) {
        console.log(`BEFORE INSERT -> ${JSON.stringify(event.entity)}`);
    }
    afterInsert(event: InsertEvent<any>) {
        console.log(`AFTER INSERT -> ${JSON.stringify(event.entity)}`);
    }
}

Now let’s say we have a Post entity:

@Entity()
export class Post {
    @PrimaryGeneratedColumn()
    id: number;
    @Column()
    title: string;
}

We create a Post and save it to the database:

let post = new Post();
post.title = "A first post";
await connection.manager.save(post);

The output is, as we expect, the following:

BEGIN TRANSACTION
BEFORE INSERT -> {"title":"A first post"}
INSERT INTO "post"("title") VALUES (?) -- PARAMETERS: ["A first post"]
AFTER INSERT -> {"title":"A first post","id":1}
COMMIT

Now let’s add a Version column to our Post entity:

@Entity()
export class Post {
    @PrimaryGeneratedColumn()
    id: number;
    @Column()
    title: string;
    @VersionColumn()
    version: number;
}

Again we create a Post and save it to the database:

let post = new Post();
post.title = "A second post";
await connection.manager.save(post);

The output is, as we don’t expect, the following:

BEGIN TRANSACTION
BEFORE INSERT -> {"title":"A second post"}
INSERT INTO "post"("title", "version") VALUES (?, 1) -- PARAMETERS: ["A second post"]
SELECT "Post"."id" AS "Post_id", "Post"."version" AS "Post_version" FROM "post" "Post" WHERE "Post"."id" = ? -- PARAMETERS: [1]
AFTER LOAD -> {"id":1,"version":1}
AFTER INSERT -> {"title":"A second post","id":1,"version":1}
COMMIT

The afterLoad event is triggered, but should not be, as the SELECT here is an internal behaviour of TypeOrm part of the overall Save operation (To further underline the wrong behaviour here, the afterLoad event receives as a parameter an object which is not an entity, but an anonymous structure {"id":1,"version":1}).

Correct behaviour should be that the afterLoad event be triggered only as a result of a find() query or a SELECT query from a QueryBuilder.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
jfarrin1commented, Jul 3, 2019

Has there been any update on this?

I am experiencing the same issue where my @AfterLoad receives relation entities as just {id: 1234} without any other properties.

1reaction
nicomousscommented, May 2, 2019

I was using the last stable version published on npm registry: 0.2.16 Now version 0.2.17 has been published, which I upgraded to, but the same behaviour remains.

Please find below the code I use to reproduce the issue:

let post = new Post();
post.title = "My post";
console.log("### save() ###");
await entityManager.save(post);

console.log("### findOne() ###");
let myPost = entityManager.getRepository(Post).findOne(post.id);

console.log("### save() ###");
myPost.title = "My new title";
await entityManager.save(myPost);

Which code outputs the following:

### save() ###
AFTER LOAD -> {"id":1,"version":1}
### findOne() ###
AFTER LOAD -> {"id":1,"title":"My post"}
### save() ###
AFTER LOAD -> {"id":1,"title":"My post"}
AFTER LOAD -> {"id":1,"version":2}

Also if we don’t use any version number, still there is an afterLoad event triggered when we save an entity (see the first afterLoad event triggered in the second save() in the example above - knowing that internally typeorm is doing a SELECT before its UPDATE, but that should be transparent here). The only afterLoad event triggered should be the one after the findOne() call.

Read more comments on GitHub >

github_iconTop Results From Across the Web

TypeORM EventSubscribe triggered at any event
Hi have created a EventSubscriber in TypeORM to listen to a specific entity and it's events on database level (quite straightforward).
Read more >
Database Engine events and errors - SQL Server
Consult this MSSQL error code list to find explanations for error messages for SQL Server database engine events.
Read more >
Pattern: Event sourcing - Microservice Architecture
The application reconstructs an entity's current state by replaying the events. Applications persist events in an event store, which is a database of...
Read more >
How to intercept entity changes with Hibernate event listeners
The most popular CDC method is to use database triggers. ... To intercept the entity insert event, we can use the following ...
Read more >
Common .NET Software Errors and How to Fix Them - Stackify
To fix the problem, look at definitions of the object types. In Visual Studio, do this by putting your cursor over the object's...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found