- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
4.3.6. Perform Database Operations in a Service
In this chapter, you'll learn how to perform database operations in a module's service.
Run Queries#
MikroORM's entity manager is a class that has methods to run queries on the database and perform operations.
Medusa provides an InjectManager
decorator imported from @medusajs/utils
that injects a service's method with a forked entity manager.
So, to run database queries in a service:
- Add the
InjectManager
decorator to the method. - Add as a last parameter an optional
sharedContext
parameter that has theMedusaContext
decorator imported from@medusajs/utils
. This context holds database-related context, including the manager injected byInjectManager
For example, in your service, add the following methods:
1// other imports...2import { 3 InjectManager,4 MedusaContext,5} from "@medusajs/framework/utils"6 7class HelloModuleService {8 // ...9 10 @InjectManager()11 async getCount(12 @MedusaContext() sharedContext?: Context<EntityManager>13 ): Promise<number> {14 return await sharedContext.manager.count("my_custom")15 }16 17 @InjectManager()18 async getCountSql(19 @MedusaContext() sharedContext?: Context<EntityManager>20 ): Promise<number> {21 const data = await sharedContext.manager.execute(22 "SELECT COUNT(*) as num FROM my_custom"23 ) 24 25 return parseInt(data[0].num)26 }27}
You add two methods getCount
and getCountSql
that have the InjectManager
decorator. Each of the methods also accept the sharedContext
parameter which has the MedusaContext
decorator.
The entity manager is injected to the sharedContext.manager
property, which is an instance of EntityManager from the @mikro-orm/knex package.
You use the manager in the getCount
method to retrieve the number of records in a table, and in the getCountSql
to run a PostgreSQL query that retrieves the count.
Execute Operations in Transactions#
To wrap database operations in a transaction, you create two methods:
- A private or protected method that's wrapped in a transaction. To wrap it in a transaction, you use the
InjectTransactionManager
decorator imported from@medusajs/utils
. - A public method that calls the transactional method. You use on it the
InjectManager
decorator as explained in the previous section.
Both methods must accept as a last parameter an optional sharedContext
parameter that has the MedusaContext
decorator imported from @medusajs/utils
. It holds database-related contexts passed through the Medusa application.
For example:
1import { 2 InjectManager,3 InjectTransactionManager,4 MedusaContext,5} from "@medusajs/framework/utils"6import { Context } from "@medusajs/framework/types"7import { EntityManager } from "@mikro-orm/knex"8 9class HelloModuleService {10 // ...11 @InjectTransactionManager()12 protected async update_(13 input: {14 id: string,15 name: string16 },17 @MedusaContext() sharedContext?: Context<EntityManager>18 ): Promise<any> {19 const transactionManager = sharedContext.transactionManager20 await transactionManager.nativeUpdate(21 "my_custom",22 {23 id: input.id,24 },25 {26 name: input.name,27 }28 )29 30 // retrieve again31 const updatedRecord = await transactionManager.execute(32 `