odavid / typeorm-transactional-cls-hooked

A Transactional Method Decorator for typeorm that uses cls-hooked to handle and propagate transactions between different repositories and service methods. Inpired by Spring Trasnactional Annotation and Sequelize CLS
MIT License
524 stars 86 forks source link

manager property is undefined when using Propagation 'SUPPORTS' #91

Closed kuldeeps48 closed 3 years ago

kuldeeps48 commented 3 years ago

When decorating method with

  @Transactional({
    propagation: Propagation.SUPPORTS,
  })

this.manager from base repository is undefined. Removing propagation fixes it.

Was working with version 0.1.12. Issue occurs from version 0.1.14

odavid commented 3 years ago

Hi, Can u post the log in debug mode? Or can u create a reproducible repository?

kuldeeps48 commented 3 years ago

Hi, Can u post the log in debug mode? Or can u create a reproducible repository?

Without propagation:

Transactional@1617031181544|default|findByDocumentNumber|undefined|REQUIRED - Before starting: isCurrentTransactionActive = undefined

query: START TRANSACTION
Transactional@1617031181544|default|findByDocumentNumber|undefined|REQUIRED - runWithNewTransaction - set entityManager in context: isCurrentTransactionActive: true

query: SELECT DISTINCT "distinctAlias"."Obd_doc_num" as "ids_Obd_doc_num" FROM (SELECT "Obd"."created_by" AS "Obd_created_by", "Obd"."updated_by" AS "Obd_updated_by", "Obd"."created_at" AS "Obd_created_at", "Obd"."updated_at" AS "Obd_updated_at", "Obd"."version" AS "Obd_version", "Obd"."doc_num" AS "Obd_doc_num", "Obd"."bu_code" AS "Obd_bu_code", "Obd"."fp_num" AS "Obd_fp_num", "Obd"."pty_code" AS "Obd_pty_code", "Obd"."ship_from_addr" AS "Obd_ship_from_addr", "Obd"."ship_from_type" AS "Obd_ship_from_type", "Obd"."ship_from_city_name" AS "Obd_ship_from_city_name", "Obd"."ship_to_addr" AS "Obd_ship_to_addr", "Obd"."ship_to_type" AS "Obd_ship_to_type", "Obd"."ship_to_city_name" AS "Obd_ship_to_city_name", "Obd"."route_code" AS "Obd_route_code", "Obd"."ship_scope" AS "Obd_ship_scope", "Obd"."status" AS "Obd_status", "Obd"."exp_del_date" AS "Obd_exp_del_date", "Obd"."exp_dis_date" AS "Obd_exp_dis_date", "Obd"."data" AS "Obd_data", "Obd"."cord" AS "Obd_cord", "Obd"."dlvrd_time" AS "Obd_dlvrd_time", "Obd"."del_remarks" AS "Obd_del_remarks", "Obd"."ver_remarks" AS "Obd_ver_remarks", "Obd"."ver_status" AS "Obd_ver_status", "Obd"."so_num" AS "Obd_so_num", "Obd"."po_num" AS "Obd_po_num", "Obd"."do_num" AS "Obd_do_num", "Obd"."to_num" AS "Obd_to_num", "Obd"."trp_num" AS "Obd_trp_num", "Obd"."prog_flags" AS "Obd_prog_flags", "Obd"."dlvrd_by" AS "Obd_dlvrd_by", "Obd"."ver_by" AS "Obd_ver_by", "Obd"."dlvrd_by_type" AS "Obd_dlvrd_by_type", "Obd"."ver_by_type" AS "Obd_ver_by_type", "Obd"."total_qty" AS "Obd_total_qty", "Obd"."lr_num" AS "Obd_lr_num", "Obd__party"."created_by" AS "Obd__party_created_by", "Obd__party"."updated_by" AS "Obd__party_updated_by", "Obd__party"."created_at" AS "Obd__party_created_at", "Obd__party"."updated_at" AS "Obd__party_updated_at", "Obd__party"."version" AS "Obd__party_version", "Obd__party"."code" AS "Obd__party_code", "Obd__party"."name" AS "Obd__party_name", "Obd__party"."contact" AS "Obd__party_contact", "Obd__party"."mobile" AS "Obd__party_mobile", "Obd__lineItems"."created_by" AS "Obd__lineItems_created_by", "Obd__lineItems"."updated_by" AS "Obd__lineItems_updated_by", "Obd__lineItems"."created_at" AS "Obd__lineItems_created_at", "Obd__lineItems"."updated_at" AS "Obd__lineItems_updated_at", "Obd__lineItems"."version" AS "Obd__lineItems_version", "Obd__lineItems"."id" AS "Obd__lineItems_id", "Obd__lineItems"."obd_num" AS "Obd__lineItems_obd_num", "Obd__lineItems"."mat_code" AS "Obd__lineItems_mat_code", "Obd__lineItems"."mat_name" AS "Obd__lineItems_mat_name", "Obd__lineItems"."unit_code" AS "Obd__lineItems_unit_code", "Obd__lineItems"."qty" AS "Obd__lineItems_qty", "Obd__lineItems"."qty_in_def_unit" AS "Obd__lineItems_qty_in_def_unit", "Obd__lineItems"."data" AS "Obd__lineItems_data", "Obd__obdDisputes"."created_by" AS "Obd__obdDisputes_created_by", "Obd__obdDisputes"."updated_by" AS "Obd__obdDisputes_updated_by", "Obd__obdDisputes"."created_at" AS "Obd__obdDisputes_created_at", "Obd__obdDisputes"."updated_at" AS "Obd__obdDisputes_updated_at", "Obd__obdDisputes"."version" AS "Obd__obdDisputes_version", "Obd__obdDisputes"."id" AS "Obd__obdDisputes_id", "Obd__obdDisputes"."obd_num" AS "Obd__obdDisputes_obd_num", "Obd__obdDisputes"."obd_li_id" AS "Obd__obdDisputes_obd_li_id", "Obd__obdDisputes"."mat_code" AS "Obd__obdDisputes_mat_code", "Obd__obdDisputes"."mat_name" AS "Obd__obdDisputes_mat_name", "Obd__obdDisputes"."unit_code" AS "Obd__obdDisputes_unit_code", "Obd__obdDisputes"."qty" AS "Obd__obdDisputes_qty", "Obd__obdDisputes"."reason" AS "Obd__obdDisputes_reason", "Obd__obdDisputes"."created_by_type" AS "Obd__obdDisputes_created_by_type", "Obd__obdDisputes"."updated_by_type" AS "Obd__obdDisputes_updated_by_type" FROM "tms"."t_obd" "Obd" LEFT JOIN "tms"."m_party" "Obd__party" ON "Obd__party"."code"="Obd"."pty_code"  LEFT JOIN "tms"."t_obd_li" "Obd__lineItems" ON "Obd__lineItems"."obd_num"="Obd"."doc_num"  LEFT JOIN "tms"."t_obd_dispute" "Obd__obdDisputes" ON "Obd__obdDisputes"."obd_num"="Obd"."doc_num" WHERE "Obd"."bu_code" = $1 AND "Obd"."doc_num" = $2) "distinctAlias"  ORDER BY "Obd_doc_num" ASC LIMIT 1 -- PARAMETERS: ["APC","OBD-0000001"]

query: SELECT "Obd"."created_by" AS "Obd_created_by", "Obd"."updated_by" AS "Obd_updated_by", "Obd"."created_at" AS "Obd_created_at", "Obd"."updated_at" AS "Obd_updated_at", "Obd"."version" AS "Obd_version", "Obd"."doc_num" AS "Obd_doc_num", "Obd"."bu_code" AS "Obd_bu_code", "Obd"."fp_num" AS "Obd_fp_num", "Obd"."pty_code" AS "Obd_pty_code", "Obd"."ship_from_addr" AS "Obd_ship_from_addr", "Obd"."ship_from_type" AS "Obd_ship_from_type", "Obd"."ship_from_city_name" AS "Obd_ship_from_city_name", "Obd"."ship_to_addr" AS "Obd_ship_to_addr", "Obd"."ship_to_type" AS "Obd_ship_to_type", "Obd"."ship_to_city_name" AS "Obd_ship_to_city_name", "Obd"."route_code" AS "Obd_route_code", "Obd"."ship_scope" AS "Obd_ship_scope", "Obd"."status" AS "Obd_status", "Obd"."exp_del_date" AS "Obd_exp_del_date", "Obd"."exp_dis_date" AS "Obd_exp_dis_date", "Obd"."data" AS "Obd_data", "Obd"."cord" AS "Obd_cord", "Obd"."dlvrd_time" AS "Obd_dlvrd_time", "Obd"."del_remarks" AS "Obd_del_remarks", "Obd"."ver_remarks" AS "Obd_ver_remarks", "Obd"."ver_status" AS "Obd_ver_status", "Obd"."so_num" AS "Obd_so_num", "Obd"."po_num" AS "Obd_po_num", "Obd"."do_num" AS "Obd_do_num", "Obd"."to_num" AS "Obd_to_num", "Obd"."trp_num" AS "Obd_trp_num", "Obd"."prog_flags" AS "Obd_prog_flags", "Obd"."dlvrd_by" AS "Obd_dlvrd_by", "Obd"."ver_by" AS "Obd_ver_by", "Obd"."dlvrd_by_type" AS "Obd_dlvrd_by_type", "Obd"."ver_by_type" AS "Obd_ver_by_type", "Obd"."total_qty" AS "Obd_total_qty", "Obd"."lr_num" AS "Obd_lr_num", "Obd__party"."created_by" AS "Obd__party_created_by", "Obd__party"."updated_by" AS "Obd__party_updated_by", "Obd__party"."created_at" AS "Obd__party_created_at", "Obd__party"."updated_at" AS "Obd__party_updated_at", "Obd__party"."version" AS "Obd__party_version", "Obd__party"."code" AS "Obd__party_code", "Obd__party"."name" AS "Obd__party_name", "Obd__party"."contact" AS "Obd__party_contact", "Obd__party"."mobile" AS "Obd__party_mobile", "Obd__lineItems"."created_by" AS "Obd__lineItems_created_by", "Obd__lineItems"."updated_by" AS "Obd__lineItems_updated_by", "Obd__lineItems"."created_at" AS "Obd__lineItems_created_at", "Obd__lineItems"."updated_at" AS "Obd__lineItems_updated_at", "Obd__lineItems"."version" AS "Obd__lineItems_version", "Obd__lineItems"."id" AS "Obd__lineItems_id", "Obd__lineItems"."obd_num" AS "Obd__lineItems_obd_num", "Obd__lineItems"."mat_code" AS "Obd__lineItems_mat_code", "Obd__lineItems"."mat_name" AS "Obd__lineItems_mat_name", "Obd__lineItems"."unit_code" AS "Obd__lineItems_unit_code", "Obd__lineItems"."qty" AS "Obd__lineItems_qty", "Obd__lineItems"."qty_in_def_unit" AS "Obd__lineItems_qty_in_def_unit", "Obd__lineItems"."data" AS "Obd__lineItems_data", "Obd__obdDisputes"."created_by" AS "Obd__obdDisputes_created_by", "Obd__obdDisputes"."updated_by" AS "Obd__obdDisputes_updated_by", "Obd__obdDisputes"."created_at" AS "Obd__obdDisputes_created_at", "Obd__obdDisputes"."updated_at" AS "Obd__obdDisputes_updated_at", "Obd__obdDisputes"."version" AS "Obd__obdDisputes_version", "Obd__obdDisputes"."id" AS "Obd__obdDisputes_id", "Obd__obdDisputes"."obd_num" AS "Obd__obdDisputes_obd_num", "Obd__obdDisputes"."obd_li_id" AS "Obd__obdDisputes_obd_li_id", "Obd__obdDisputes"."mat_code" AS "Obd__obdDisputes_mat_code", "Obd__obdDisputes"."mat_name" AS "Obd__obdDisputes_mat_name", "Obd__obdDisputes"."unit_code" AS "Obd__obdDisputes_unit_code", "Obd__obdDisputes"."qty" AS "Obd__obdDisputes_qty", "Obd__obdDisputes"."reason" AS "Obd__obdDisputes_reason", "Obd__obdDisputes"."created_by_type" AS "Obd__obdDisputes_created_by_type", "Obd__obdDisputes"."updated_by_type" AS "Obd__obdDisputes_updated_by_type" FROM "tms"."t_obd" "Obd" LEFT JOIN "tms"."m_party" "Obd__party" ON "Obd__party"."code"="Obd"."pty_code"  LEFT JOIN "tms"."t_obd_li" "Obd__lineItems" ON "Obd__lineItems"."obd_num"="Obd"."doc_num"  LEFT JOIN "tms"."t_obd_dispute" "Obd__obdDisputes" ON "Obd__obdDisputes"."obd_num"="Obd"."doc_num" WHERE ( "Obd"."bu_code" = $1 AND "Obd"."doc_num" = $2 ) AND ( "Obd"."doc_num" IN ($3) ) -- PARAMETERS: ["APC","OBD-0000001","OBD-0000001"]
Transactional@1617031181544|default|findByDocumentNumber|undefined|REQUIRED - runWithNewTransaction - Success
Transactional@1617031181544|default|findByDocumentNumber|undefined|REQUIRED - runWithNewTransaction - reset entityManager in context

With propagation SUPPORTS:

Transactional@1617031345805|default|findByDocumentNumber|undefined|SUPPORTS - Before starting: isCurrentTransactionActive = undefined
29/3/2021, 8:52:25 pm: ERROR_LOG) GraphQL Server >>  Error: Cannot read property 'getRepository' of undefined
Stack: TypeError: Cannot read property 'getRepository' of undefined
    at OutboundDeliveryTypeormRepository.findByDocumentNumber (/home/admininstrator/JavaScript Workspace/admin-server/dist/infrastructure/dispatch/ftl/obd/outbound-delivery-typeorm-repository.js:216:43)
    at OutboundDeliveryTypeormRepository.<anonymous> (/home/admininstrator/JavaScript Workspace/admin-server/node_modules/typeorm-transactional-cls-hooked/dist/Transactional.js:83:43)
    at step (/home/admininstrator/JavaScript Workspace/admin-server/node_modules/typeorm-transactional-cls-hooked/dist/Transactional.js:33:23)
    at Object.next (/home/admininstrator/JavaScript Workspace/admin-server/node_modules/typeorm-transactional-cls-hooked/dist/Transactional.js:14:53)
    at /home/admininstrator/JavaScript Workspace/admin-server/node_modules/typeorm-transactional-cls-hooked/dist/Transactional.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/home/admininstrator/JavaScript Workspace/admin-server/node_modules/typeorm-transactional-cls-hooked/dist/Transactional.js:4:12)
    at runOriginal (/home/admininstrator/JavaScript Workspace/admin-server/node_modules/typeorm-transactional-cls-hooked/dist/Transactional.js:82:52)
    at /home/admininstrator/JavaScript Workspace/admin-server/node_modules/typeorm-transactional-cls-hooked/dist/hook.js:64:28
    at step (/home/admininstrator/JavaScript Workspace/admin-server/node_modules/typeorm-transactional-cls-hooked/dist/hook.js:33:23)

Looks like entity manager is not set if propagation is SUPPORTS

 case Propagation.SUPPORTS:
            if (currentTransaction) {
              return runOriginal()
            } else {
              return runWithNewHook()
            }

setEntityManagerForConnection(connectionName, context, entityManager) is not called in runOriginal or runWithNewHook and since i'm trying to access manager, i get undefined.

odavid commented 3 years ago

Hi, setEntityManagerForConnection() should be called ONLY if Transactional is starting a transaction. Since it is not starting, it should not set it.

I tried to run it myself, and it works for me.

If you look at: https://github.com/odavid/typeorm-transactional-cls-hooked/blob/master/src/common.ts#L16 you will see that the the getEntityManagerOrTransactionManager function returns the original entityManager as default.

In versions previous to 0.12, it created an entityManager, which was wrong.

It seems to me there is an issue with the repository injection.

What happens if you remove the decorator at all?

kuldeeps48 commented 3 years ago

Hi, setEntityManagerForConnection() should be called ONLY if Transactional is starting a transaction. Since it is not starting, it should not set it.

I tried to run it myself, and it works for me.

If you look at: https://github.com/odavid/typeorm-transactional-cls-hooked/blob/master/src/common.ts#L16 you will see that the the getEntityManagerOrTransactionManager function returns the original entityManager as default.

In versions previous to 0.12, it created an entityManager, which was wrong.

It seems to me there is an issue with the repository injection.

What happens if you remove the decorator at all?

Hi, It works fine when I remove the decorator. So it's explicitly not setting the manager property when I decorate with SUPPORTS? Do I need to perform a check if the manager is set otherwise use the global manager? That would be such a pain.