Entity_manager
Chapter 15: Entity Manager & Repository Differences
Section titled “Chapter 15: Entity Manager & Repository Differences”Understanding Entity Manager vs Repository
Section titled “Understanding Entity Manager vs Repository”15.1 Overview
Section titled “15.1 Overview”Both Entity Manager and Repository provide data access, but they differ in scope and usage.
Entity Manager vs Repository ================================================================================
Entity Manager Repository +---------------------------+ +---------------------------+ | | | | | Central point for ALL | | Dedicated to ONE | | entities | | entity | | | | | | +---------------------+ | | +---------------------+ | | | find(User) | | | | find() | | | | find(Post) | | | | findOne() | | | | find(Comment) | | | | save() | | | | ... | | | | remove() | | | +---------------------+ | | +---------------------+ | | | | | | Must specify entity type | | Entity type implicit | | | | | +---------------------------+ +---------------------------+
================================================================================15.2 Entity Manager
Section titled “15.2 Entity Manager”Getting Entity Manager
Section titled “Getting Entity Manager”import { AppDataSource } from './data-source';
// From DataSourceconst entityManager = AppDataSource.manager;
// From Repositoryconst entityManager = userRepository.manager;
// Create new QueryRunnerconst queryRunner = AppDataSource.createQueryRunner();const entityManager = queryRunner.manager;Entity Manager Methods
Section titled “Entity Manager Methods”import { EntityManager } from 'typeorm';import { User } from './entities/user.entity';import { Post } from './entities/post.entity';
async function entityManagerExamples(manager: EntityManager) { // Find const users = await manager.find(User); const posts = await manager.find(Post);
// Find with conditions const activeUsers = await manager.find(User, { where: { isActive: true }, });
// Find one const user = await manager.findOne(User, { where: { id: 1 }, });
// Save const newUser = manager.create(User, { name: 'John', email: 'john@example.com', }); await manager.save(newUser);
// Remove await manager.remove(user);
// Delete await manager.delete(User, { id: 1 });
// Update await manager.update(User, { id: 1 }, { name: 'Updated' });
// Count const count = await manager.count(User);
// Raw query const result = await manager.query('SELECT * FROM users');
// Query builder const qb = manager.createQueryBuilder(User, 'user');
// Transaction await manager.transaction(async (tm) => { // tm is another EntityManager await tm.save(User, { name: 'User 1' }); await tm.save(Post, { title: 'Post 1' }); });}15.3 Repository
Section titled “15.3 Repository”Getting Repository
Section titled “Getting Repository”import { AppDataSource } from './data-source';import { User } from './entities/user.entity';
// From DataSourceconst userRepository = AppDataSource.getRepository(User);
// From Entity Managerconst userRepository = AppDataSource.manager.getRepository(User);
// In NestJS@Injectable()export class UsersService { constructor( @InjectRepository(User) private userRepository: Repository<User>, ) {}}Repository Methods
Section titled “Repository Methods”import { Repository } from 'typeorm';import { User } from './entities/user.entity';
async function repositoryExamples(repository: Repository<User>) { // Find (entity type implicit) const users = await repository.find();
// Find with conditions const activeUsers = await repository.find({ where: { isActive: true }, });
// Find one const user = await repository.findOne({ where: { id: 1 }, });
// Create const newUser = repository.create({ name: 'John', email: 'john@example.com', }); await repository.save(newUser);
// Remove await repository.remove(user);
// Delete await repository.delete({ id: 1 });
// Update await repository.update({ id: 1 }, { name: 'Updated' });
// Count const count = await repository.count();
// Query builder const qb = repository.createQueryBuilder('user');}15.4 Key Differences
Section titled “15.4 Key Differences” Entity Manager vs Repository Comparison +------------------------------------------------------------------+ | | | Aspect | Entity Manager | Repository | | -------------------|-------------------|----------------------| | Scope | All entities | Single entity | | Type specification | Required | Implicit | | Best for | Cross-entity ops | Single entity ops | | Transactions | Built-in | Via manager | | Custom methods | Not possible | Extendable | | Dependency Inj. | Less common | Common pattern | | Type safety | Less strict | More strict | | | +------------------------------------------------------------------+When to Use Entity Manager
Section titled “When to Use Entity Manager”// 1. Cross-entity operationsasync function transferData(manager: EntityManager) { const users = await manager.find(User); const posts = await manager.find(Post); // Work with both entities}
// 2. Transactions with multiple entitiesasync function createUserWithPosts(manager: EntityManager) { await manager.transaction(async (tm) => { const user = tm.create(User, { name: 'John' }); await tm.save(user);
const post = tm.create(Post, { title: 'First Post', author: user }); await tm.save(post); });}
// 3. Raw SQL queriesasync function executeRawQuery(manager: EntityManager) { const result = await manager.query(` SELECT u.*, COUNT(p.id) as post_count FROM users u LEFT JOIN posts p ON u.id = p.author_id GROUP BY u.id `); return result;}
// 4. Dynamic entity operationsasync function dynamicOperation( manager: EntityManager, entityName: string,) { const entity = getEntityByName(entityName); return manager.find(entity);}When to Use Repository
Section titled “When to Use Repository”// 1. Single entity operationsasync function getUsers(repository: Repository<User>) { return repository.find();}
// 2. Custom query methodsexport class UserRepository extends Repository<User> { async findActive(): Promise<User[]> { return this.find({ where: { isActive: true } }); }}
// 3. Dependency injection pattern@Injectable()export class UsersService { constructor( @InjectRepository(User) private usersRepository: Repository<User>, ) {}}
// 4. Type-safe operationsasync function findUser(id: number, repository: Repository<User>) { return repository.findOne({ where: { id } }); // Return type is User | null}15.5 Working with Both
Section titled “15.5 Working with Both”Combining Entity Manager and Repository
Section titled “Combining Entity Manager and Repository”import { Injectable } from '@nestjs/common';import { InjectRepository } from '@nestjs/typeorm';import { InjectDataSource } from '@nestjs/typeorm';import { Repository, DataSource, EntityManager } from 'typeorm';import { User } from './user.entity';import { Post } from './post.entity';
@Injectable()export class UsersService { constructor( @InjectRepository(User) private userRepository: Repository<User>, @InjectRepository(Post) private postRepository: Repository<Post>, @InjectDataSource() private dataSource: DataSource, ) {}
// Using repositories async findUser(id: number) { return this.userRepository.findOne({ where: { id } }); }
// Using entity manager for cross-entity async getUserWithStats(id: number) { return this.dataSource.manager .createQueryBuilder(User, 'user') .leftJoin('user.posts', 'post') .select(['user.id', 'user.name']) .addSelect('COUNT(post.id)', 'postCount') .where('user.id = :id', { id }) .groupBy('user.id') .getRawOne(); }
// Transaction with both async createUserWithPosts(userData: any, postsData: any[]) { return this.dataSource.transaction(async (manager) => { // Use manager for transaction const user = manager.create(User, userData); await manager.save(user);
// Or use repository's manager const posts = this.postRepository.create( postsData.map(p => ({ ...p, author: user })) ); await manager.save(posts);
return user; }); }}15.6 Transaction Patterns
Section titled “15.6 Transaction Patterns”Using Entity Manager
Section titled “Using Entity Manager”// Method 1: transaction() with callbackawait entityManager.transaction(async (manager) => { await manager.save(User, { name: 'User 1' }); await manager.save(Post, { title: 'Post 1' });});
// Method 2: Manual transaction controlconst queryRunner = dataSource.createQueryRunner();await queryRunner.connect();await queryRunner.startTransaction();
try { await queryRunner.manager.save(User, { name: 'User 1' }); await queryRunner.manager.save(Post, { title: 'Post 1' }); await queryRunner.commitTransaction();} catch (error) { await queryRunner.rollbackTransaction(); throw error;} finally { await queryRunner.release();}Using Repository
Section titled “Using Repository”// Repository uses its manager for transactionsawait userRepository.manager.transaction(async (manager) => { const user = manager.create(User, { name: 'User 1' }); await manager.save(user);
const post = manager.create(Post, { title: 'Post 1', author: user }); await manager.save(post);});15.7 Performance Considerations
Section titled “15.7 Performance Considerations” Performance Comparison +------------------------------------------------------------------+ | | | Operation | Entity Manager | Repository | | -------------------|----------------|------------------------| | Single entity find | Similar | Similar | | Multi-entity ops | Better | Multiple repos needed | | Transactions | Native | Via manager | | Type inference | Slower | Faster | | Memory usage | Higher | Lower | | | +------------------------------------------------------------------+15.8 Best Practices
Section titled “15.8 Best Practices” Best Practices +------------------------------------------------------------------+ | | | 1. Use Repository for single entity operations | | - Cleaner code | | - Better type safety | | - Dependency injection friendly | | | | 2. Use Entity Manager for cross-entity operations | | - Single transaction scope | | - Consistent data access | | | | 3. Use Entity Manager for transactions | | - Atomic operations | | - Automatic rollback | | | | 4. Extend Repository for custom methods | | - Encapsulate complex queries | | - Reusable logic | | | | 5. Don't mix both in same operation | | - Choose one approach | | - Be consistent | | | +------------------------------------------------------------------+15.9 Summary
Section titled “15.9 Summary” Quick Reference +------------------------------------------------------------------+ | | | Use Entity Manager when: | | - Working with multiple entities | | - Need transactions | | - Executing raw SQL | | - Dynamic entity operations | | | | Use Repository when: | | - Working with single entity | | - Need custom query methods | | - Using dependency injection | | - Want cleaner, type-safe code | | | +------------------------------------------------------------------+Next Chapter
Section titled “Next Chapter”Chapter 16: Query Builder Fundamentals
Last Updated: February 2026