odavid/typeorm-transactional-cls-hooked

Suggestion: clarity in documentation

alsonkemp opened this issue · 9 comments

I appreciate the project and am trying to use it for something slightly outside its main use case: wrap an entire Express request-response in a transaction (as in Django) and I'm not clear how to do so...

Is the Transactional annotation required in all cases or will a BaseEntity use a CLS-transaction if it's available? I guess the question is: how is a CLS-txn started?; what uses a CLS-txn?

+1

I would also like to happen if its enough to patch the repositories and having one transactional decorator to have any methods using the repository after the decorator to use the same trx.

Hi @alsonkemp!

If I understand you correctly, you will need to follow the steps in the README to set up a custom repository, and then use @Transactional() in all methods that call database operations.

Note that you need to use the custom repository for database operations, since calls to Entity.save() method will run inside an independent transaction (and might break your application).

The default propagation level for transaction is REQUIRED, which means that that method's will use the existing transaction if called from a method with an active transaction, or create a new one.

@alsonkemp, I'm checking with @odavid if a class decorator makes sense in this lib. However, #41 contains a custom class decorator implementation that would work.

@willianscfa i wound up writing a custom express wrapper. Mostly detailed here: typeorm/typeorm#6823

I'm trying to integrate this because it seems like a really elegant approach to organizing transactions, and am running into some issues of clarity from the README like @alsonkemp. @cassinaooo , you said:

use @Transactional() in all methods that call database operations."

If you patch TypeORM Repository with BaseRepository, what scenarios are not covered? Can I do getManager().createQueryBuilder(MyEntity) and expect the @Transactional to cover it? What about createQueryRunner, so long as I am only touching Entities that use BaseRepository? Are there any caveats with relations?

Is there any way to grab the transactional context that is established by the decorator to use in functions that do not / cannot employ the decorator? Eg, can I safely do getRepository(MyEntity).manager, pass that manager to another function, and expect the transactional context to hold for that manager?

@mscottnelson See typeorm/typeorm#6823 for how I wound up handling this. I can provide more details if you like.

Can I do getManager().createQueryBuilder(MyEntity) and expect the @transactional to cover it?

Managers / QueryBuilders obtained using the patched repository run inside the transaction in my experience.

I usually do something like this.customRepositoryInstance.createQueryBuilder(...) and it works just fine.

So this following is expected to don't run inside transactions, right?

await getConnection()
    .createQueryBuilder()
    .insert()
    .into(User)
    .values([
        { firstName: "Timber", lastName: "Saw" }, 
        { firstName: "Phantom", lastName: "Lancer" }
     ])
    .execute();

I've been using this lib with https://github.com/w3tecch/typeorm-seeding and when using its connection value to create the QueryBuilder this query don't rolls back

@micalevisk that is mostly correct, I think... The rollback functionality is coupled to the Repository Manager (which, can include all repos if you use the monkey-patch of the base TypeORM classes). Therefore, if you do not use a patched repository, then the @transactional is not applied.

I'm not sure about the specific semantics of into in this scenario. You might consider whether you can get away with a pattern like: await getRepository(User)... and chain from there, to reduce this ambiguity in the absence of additional clarification from @odavid