typeorm: beforeUpdate subscriber entity argument is undefined
Issue type:
[ ] question [X] bug report [ ] feature request [ ] documentation issue
Database system/driver:
[ ] cordova
[ ] mongodb
[ ] mssql
[ ] mysql
/ mariadb
[ ] oracle
[ ] postgres
[ ] cockroachdb
[X] sqlite
[ ] sqljs
[ ] react-native
[ ] expo
TypeORM version:
[ ] latest
[ ] @next
[X] typeorm@0.2.19
(or put your version here)
Steps to reproduce or a small repository showing the problem:
@EventSubscriber()
export class UpdateModifiedSubscriber implements EntitySubscriberInterface {
beforeUpdate ( event: UpdateEvent<any> ) {
if ( ( event.entity as IEntityBase ) != null )
( event.entity as IEntityBase ).dateModified = new Date();
}
beforeInsert ( event: InsertEvent<any> ) {
if ( ( event.entity as IEntityBase ) != null )
( event.entity as IEntityBase ).dateModified = new Date();
}
}
export interface IEntityBase {
id?: string;
dateModified?: Date;
}
export abstract class EntityBase<T> implements IEntityBase {
constructor ();
constructor ( entity: Partial<T> );
constructor ( entity?: any ) {
if ( !entity ) return;
for ( const key in entity )
this[ key ] = entity[ key ];
}
@PrimaryGeneratedColumn( 'uuid' )
id: string;
@Column( { type: dateTimeType(), nullable: true } )
dateModified: Date;
}
@Entity( 'Player' )
export class Player extends EntityBase<IPlayer> implements IPlayer {
@Column( { type: 'nvarchar', length: 20, nullable: false } )
firstName: string;
@Column( { type: 'nvarchar', length: 20, nullable: false } )
lastName: string;
@Column( { type: 'integer', nullable: false } )
jerseyNumber: number;
@Column( { type: 'integer', nullable: false } )
weight: number;
@Column( { type: 'text', nullable: true } )
stats?: string;
@Column( { nullable: false } )
teamId: string;
/**
* The players complete name
*
* @readonly
* @memberof Player
*/
get fullName () { return `${ this.firstName } ${ this.lastName }`; }
}
async update ( playerId: string, player: Partial<Player> ): Promise<boolean> {
// test that the a record to update exists in the database
let existingPlayer: Player;
try {
existingPlayer = await this
.connection
.getRepository( Player )
.findOneOrFail( playerId );
} catch ( error ) {
throw new BadRequest( error );
}
try {
if ( process.env.DATABASE_TYPE && process.env.DATABASE_TYPE == 'sqlite' ) {
Object.keys( player ).forEach( prop => {
if ( existingPlayer.hasOwnProperty( prop ) )
existingPlayer[ prop ] = player[ prop ];
} );
// I absolutely do NOT like this. It smells to me. However, I wonder if sql server driver eventually does
// the same thing here with output clause by select query after the update.
let updateResult = await this.connection
.getRepository( Player )
.update( playerId, existingPlayer );
// await this.connection
// .createQueryBuilder()
// .update( Player )
// .set( player )
// .where( "id = :id", { id: playerId } )
// .execute();
let updatedPlayer = await this
.connection
.getRepository( Player )
.findOne( playerId );
return isMatch( updatedPlayer, player );
} else {
// so we are going to use mssql output clause to return updated cols and values then test that instead of
// running seperate additional select query to see if all updated cols were success
let result = await this.connection
.createQueryBuilder()
.update( Player )
.set( player )
.where( "id = :id", { id: playerId } )
.output( Object.keys( player ) )
.execute();
if ( result.raw && result.raw.length > 0 )
return isEqual( result.raw[ 0 ], player );
}
} catch ( error ) {
throw new BadRequest( error );
}
return false;
}
The update method shows a few different things I have tried in order to perform the partial update. I would expect the commented out querybuilder code to work. I understand I can result to using the save
repo method but I would like the partial support and optimized primitive query. I tried mssql
driver and it works as expected. It is also much more convenient as you can see the code simply need just test the update query results to see if update was a success. However, I must use sqlite
and I understand there is no output clause. To test if success update I am selecting the record after the update then testing that. All the beforeInsert
subscribers work as expected however the beforeUpdate
doesn’t pass the event.entity and therefore I cannot update the dateModified
.
Is there a different or better way to do this. I absolutely love typeorm
and will work around this issue, however, it would be nice to have more concise partial update code to implement expressjs
server patch routes. I have not had the time to scour the queryRunner
manager
or metadata
and it is not clear to me what if any I can update in order to pass the new date to the query in the subscriber method.
I apologize for the example code not being complete and I hope there is enough there to see the issue. I tried the beforeUpdate subscriber in a older project where I also used typeorm and the same issue exists. I wondered if the metadata of the inheritance and stuff might of been a issue.
I will try to write some tests for the listeners soon and will update here on that or offer a PR.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 22 (7 by maintainers)
Commits related to this issue
- fix: issue entity object not passed to subscriber Closes: #4947 — committed to RuntimeRascal/typeorm by RuntimeRascal 4 years ago
- fix: issue entity object not passed to subscriber Closes: #4947 — committed to RuntimeRascal/typeorm by RuntimeRascal 4 years ago
- fix: entity object undefined in update subscriber Closes: #4947 — committed to RuntimeRascal/typeorm by RuntimeRascal 4 years ago
- fix: entity object undefined in update subscriber (#5443) * fix: entity object undefined in update subscriber Closes: #4947 * refactor: remove not neccasarry code from test * refactor: refac... — committed to typeorm/typeorm by RuntimeRascal 4 years ago
So I finally tracked down the lines I needed to change and was able to locally fix the issue 😃
NOTE: I’m NOT sure this will work universally for everyone, but it MAY work as a temporary workaround. I do plan to attempt to do a proper PR today if I get the chance.
NOTE: This is for version
0.2.22
ofTypeORM
, I’m not sure if this will work or break with other versions!For those that want to try using
patch-package
(how I was able to fix it for now), follow these steps:patch-package
globally (or locally in your project, not sure if it matters but I’ve installed it globally and locally)patches/typeorm+0.2.22.patch
(in your root project directory. I,e [rootDir]/patches/typeorm+0.2.22.patch`) with the following contents:package.json
:yarn
/yarn install
ornpm i
entity
value from thebeforeUpdate
orafterUpdate
you should see the changes you made in the returned objectdatabaseEntity
, not sure if there’s a way to do that or not