Skip to content

Commit

Permalink
feat: add InjectEntityManager decorator for MikroORM and upgrade docu…
Browse files Browse the repository at this point in the history
…ment (#3114)

* feat: added `InjectEntityManager` for mikro-orm

* chore(docs): updated documents for mikro-orm

* chore(test): added test case for `InjectEntityManager`

* chore(test): updated test according to the guideline of mikro-orm
  • Loading branch information
ghostoy authored Aug 5, 2023
1 parent b30b188 commit dd7b48f
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 44 deletions.
20 changes: 19 additions & 1 deletion packages/mikro/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import {
Init,
Inject,
} from '@midwayjs/core';
import { DATA_SOURCE_KEY, ENTITY_MODEL_KEY } from './decorator';
import {
DATA_SOURCE_KEY,
ENTITY_MANAGER_KEY,
ENTITY_MODEL_KEY,
} from './decorator';
import { MikroDataSourceManager } from './dataSourceManager';
import { EntityName, RequestContext } from '@mikro-orm/core';

Expand Down Expand Up @@ -62,6 +66,20 @@ export class MikroConfiguration implements ILifeCycle {
}
);

this.decoratorService.registerPropertyHandler(
ENTITY_MANAGER_KEY,
(propertyName, meta: { connectionName?: string }) => {
if (RequestContext.getEntityManager()) {
return RequestContext.getEntityManager();
} else {
return this.dataSourceManager.getDataSource(
meta.connectionName ||
this.dataSourceManager.getDefaultDataSourceName()
).em;
}
}
);

this.decoratorService.registerPropertyHandler(
DATA_SOURCE_KEY,
(
Expand Down
7 changes: 7 additions & 0 deletions packages/mikro/src/decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createCustomPropertyDecorator } from '@midwayjs/core';
import { EntityName } from '@mikro-orm/core';

export const ENTITY_MODEL_KEY = 'mikro:entity_model_key';
export const ENTITY_MANAGER_KEY = 'mikro:entity_manager_key';
export const DATA_SOURCE_KEY = 'mikro:data_source_key';

export function InjectRepository(
Expand All @@ -14,6 +15,12 @@ export function InjectRepository(
});
}

export function InjectEntityManager(connectionName?: string) {
return createCustomPropertyDecorator(ENTITY_MANAGER_KEY, {
connectionName,
});
}

export function InjectDataSource(dataSourceName?: string) {
return createCustomPropertyDecorator(DATA_SOURCE_KEY, {
dataSourceName,
Expand Down
38 changes: 21 additions & 17 deletions packages/mikro/test/fixtures/base-fn-origin/src/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
import { App, Configuration, Inject } from '@midwayjs/core';
import * as mikro from '../../../../src';
import { join } from 'path';
import { InjectDataSource, InjectRepository } from '../../../../src';
import {
InjectDataSource,
InjectRepository,
InjectEntityManager,
MikroDataSourceManager,
} from '../../../../src';
import { IMidwayApplication } from '@midwayjs/core';
import { Book } from './entity';
import { EntityRepository, QueryOrder, wrap } from '@mikro-orm/core';
import { MikroORM, IDatabaseDriver, Connection } from '@mikro-orm/core';
import { EntityManager, EntityRepository } from '@mikro-orm/sqlite';
import { MikroORM, IDatabaseDriver, Connection, QueryOrder } from '@mikro-orm/core';

@Configuration({
imports: [
mikro
],
importConfigs: [
join(__dirname, './config')
]
imports: [mikro],
importConfigs: [join(__dirname, './config')],
})
export class ContainerConfiguration {
@InjectRepository(Book)
bookRepository: EntityRepository<Book>;

@InjectEntityManager()
em: EntityManager;

@App()
app: IMidwayApplication;

@Inject()
mikroDataSourceManager: mikro.MikroDataSourceManager;
mikroDataSourceManager: MikroDataSourceManager;

@InjectDataSource()
defaultDataSource: MikroORM<IDatabaseDriver<Connection>>;
Expand All @@ -32,17 +36,17 @@ export class ContainerConfiguration {
namedDataSource: MikroORM<IDatabaseDriver<Connection>>;

async onReady() {

expect(this.defaultDataSource).toBeDefined();
expect(this.defaultDataSource).toEqual(this.namedDataSource);

const orm = this.mikroDataSourceManager.getDataSource('default');
const connection = orm.em.getConnection();
await (connection as any).loadFile(join(__dirname, '../sqlite-schema.sql'));
const connection = this.em.getConnection();
await connection.loadFile(join(__dirname, '../sqlite-schema.sql'));

const book = this.bookRepository.create({ title: 'b1', author: { name: 'a1', email: 'e1' } });
wrap(book.author, true).__initialized = true;
await this.bookRepository.persist(book).flush();
const book = this.bookRepository.create({
title: 'b1',
author: { name: 'a1', email: 'e1' },
});
await this.em.persist(book).flush();

const findResult = await this.bookRepository.findAll({
populate: ['author'],
Expand Down
38 changes: 26 additions & 12 deletions site/docs/extensions/mikro.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,39 +197,53 @@ export default (appInfo) => {



### 调用 Repository
### 增删查改

在业务代码中使用 `InjectRepository` 注入 `repository` 对象,执行数据库操作。
在业务代码中,可以使用`InjectRepository`注入`Repository`对象执行简单的查询操作。其它的增删改操作可以通过配合`EntityManger``persist``flush`接口来实现,使用`InjectEntityManager`可以直接注入`EntityManager`对象,也可以通过`repository.getEntityManager()`获取。

:::caution

从5.7版本开始,MikroORM将原来`Repository``persist``flush`等接口标为*弃用*,并计划在v6版本中[彻底移除](https://github.com/mikro-orm/mikro-orm/discussions/3989),建议直接调用`EntityManager`上的相关接口。

:::

```typescript
import { Book } from './entity';
import { Provide } from '@midwayjs/core';
import { InjectRepository } from '@midwayjs/mikro';
import { EntityRepository, QueryOrder, wrap } from '@mikro-orm/core';
import { InjectEntityManager, InjectRepository } from '@midwayjs/mikro';
import { QueryOrder } from '@mikro-orm/core';
import { EntityManager, EntityRepository } from '@mikro-orm/mysql'; // 需要使用数据库驱动对应的类来执行操作

@Provide()
export class BookController {
export class BookService {

@InjectRepository(Book)
bookRepository: EntityRepository<Book>;

async findBookAndQuery() {
const book = this.bookRepository.create({ title: 'b1', author: { name: 'a1', email: 'e1' } });
wrap(book.author, true).__initialized = true;
await this.bookRepository.persist(book).flush();
@InjectEntityManager()
em: EntityManager;

const findResult = await this.bookRepository.findAll({
async queryByRepo() {
// 使用Repository查询
const books = await this.bookRepository.findAll({
populate: ['author'],
orderBy: { title: QueryOrder.DESC },
limit: 20,
});
return books;
}

async createBook() {
const book = new Book({ title: 'b1', author: { name: 'a1', email: 'e1' } });
// 标记保存Book
this.em.persist(book);
// 执行所有变更
await this.em.flush();
return book;
}
}
```



## 高级功能

### 获取数据源
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,33 +198,50 @@ For association in the form of a directory scan, please refer to [Data Source Ma



### Call Repository
### CRUD Operations

Use `InjectRepository` injection `repository` objects in business code to perform database operations.
Use `InjectRepository` to inject `Repository` to perform simple query operations. And use `InjectEntityManager` to get the instance of `EntityManager`, to perform creating, updating and deleting operations.
You can also get `EntityManager` by calling `repository.getEntityManger()`.

:::caution

Since v5.7, `persist` and `flush` etc. on `Repository` (shortcuts to methods on `EntityManager`) were marked as *deprecated*, and [planned to remove them in v6](https://github.com/mikro-orm/mikro-orm/discussions/3989). Please use those APIs on `EntityManger` directly instead of on `Repository`.

:::

```typescript
import { Book } from './entity';
import { Provide } from '@midwayjs/core';
import { InjectRepository } from '@midwayjs/mikro';
import { EntityRepository, QueryOrder, wrap } from '@mikro-orm/core';
import { InjectEntityManager, InjectRepository } from '@midwayjs/mikro';
import { QueryOrder } from '@mikro-orm/core';
import { EntityManager, EntityRepository } from '@mikro-orm/mysql'; // should be imported from driver specific packages

@Provide()
export class BookController {
export class BookService {

@InjectRepository(Book)
bookRepository: EntityRepository<Book>;

async findBookAndQuery() {
const book = this.bookRepository.create({ title: 'b1', author: { name: 'a1', email: 'e1' } });
wrap(book.author, true).__initialized = true;
await this.bookRepository.persist(book).flush();

const findResult = await this.bookRepository.findAll({
populate: ['author']
orderBy: { title: QueryOrder.DESC}
limit: 20
@InjectEntityManager()
em: EntityManager;

async queryByRepo() {
// query with Repository
const books = await this.bookRepository.findAll({
populate: ['author'],
orderBy: { title: QueryOrder.DESC },
limit: 20,
});
return books;
}

async createBook() {
const book = new Book({ title: 'b1', author: { name: 'a1', email: 'e1' } });
// mark book as persisted
this.em.persist(book);
// persist all changes to database
await this.em.flush();
return book;
}
}
```
Expand Down

0 comments on commit dd7b48f

Please sign in to comment.