nestjs / typeorm

TypeORM module for Nest framework (node.js) 🍇

Home Page:https://nestjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

createTypeOrmProviders should inject EntityManager instead of Connection

edeesis opened this issue · comments

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

createTypeOrmProviders currently injects getConnection and resolves the repositories directly from the connection. However, there are certain scenarios when you'd want to resolve the repository from the EntityManager, such as when running in a transaction.

Describe the solution you'd like

I'm proposing changing the createTypeOrmProviders function to inject the EntityManager and use that to initialize the repositories.

export function createTypeOrmProviders(
  entities?: EntityClassOrSchema[],
  dataSource?: DataSource | DataSourceOptions | string,
): Provider[] {
  return (entities || []).map((entity) => ({
    provide: getRepositoryToken(entity, dataSource),
    useFactory: (entityManager: EntityManager) => {
      const enitityMetadata = dataSource.entityMetadatas.find((meta) => meta.target === entity)
      const isTreeEntity = typeof enitityMetadata?.treeType !== 'undefined'
      return isTreeEntity 
        ? entityManager.getTreeRepository(entity)
        : entityManager.connection.options.type === 'mongodb'
          ? entityManager.getMongoRepository(entity)
          : entityManager.getRepository(entity);
    },
    inject: [getEntityManagerToken(dataSource)],
    /**
     * Extra property to workaround dynamic modules serialisation issue
     * that occurs when "TypeOrm#forFeature()" method is called with the same number
     * of arguments and all entities share the same class names.
     */
    targetEntitySchema: getMetadataArgsStorage().tables.find(
      (item) => item.target === entity,
    ),
  }));
}

Teachability, documentation, adoption, migration strategy

This should theoretically be a non-breaking change to all users of the library. We're merely changing which object we're calling getRepository on. In fact, DataSource's getRepository method just proxies to the manager anyway.

What is the motivation / use case for changing the behavior?

The instance of manager changes when you open a transaction. That manager instance has to be used to generate the repository, otherwise the transaction is ignored.

Currently, the only method for working around this is overriding each Repository provider. This would allow someone to override the EntityManager and then all repositories created will use that manager instance.

Let's track this here #1820