MikroORM:如何忽略flush()上的重复条目

问题描述 投票:0回答:1

在调用

flush()
时,有没有办法忽略重复条目(通常是 MySQL/MariaDB 上的 1062 SQL 错误)?

如果条目存在,是否有办法让 EntityManager 使用现有行以新引用覆盖实体并继续工作单元?

如果没有,最好的解决方案是编写我自己的函数到

findOne()
,然后添加到实体图中吗?

感谢您的帮助!

编辑1: 例如,如果找到的话,是否会因为不持久而导致任何失败?也许是这样的函数......

  /**
   * 
   * @param em an EntityManager
   * @param ent an Entity that is already populated and ready to be persisted.
   * @param collision field and value for potential duplicate.
   * @returns the referenced entity to be used in an entity graph if necessary
   */
  async persistOrIgnore<T extends AnyEntity<T>>(em: EntityManager, ent: Loaded<T>, collision: ObjectQuery<T>): Promise<Loaded<T>> {
    const entName = ent.__meta?.className;
    const found = await em.findOne(entName, collision);
    if (!found) em.persist(ent);
    return found || ent;
  }

然后像这样使用:

const order = new Order(); //parent to persist

let contents = new OrderContents(); // new entity
contents.checksum = 'xxx' // unique field that will produce 1062 SQL error
// [...add other properties you would like to persist.]
  
contents = await persistOrIgnore(em, contents, { checksum: contents.checksum });

order.contentsId = contents;
em.persist(order);

// [...do more work, e.g. add more to the parent order entity]

await em.flush();

编辑2: v5.5.0 中现在有更新插入功能:

https://mikro-orm.io/docs/entity-manager#upsert

mariadb nestjs mikro-orm
1个回答
2
投票

你不能,你有责任在上下文(身份映射)中拥有有效的状态。您应该使用 QB 进行更新插入,支持

on conflict
查询。

const qb = em.createQueryBuilder(User)
  .insert({
    email: '[email protected]',
    name: 'John Doe',
  })
  .onConflict('email').ignore();

在 QB 测试中查看更多示例:

https://github.com/mikro-orm/mikro-orm/blob/master/tests/QueryBuilder.test.ts#L1327

或者查看 knex 文档,因为 API 是基于它设计的(并且只是基本包装了它):

https://knexjs.org/guide/query-builder.html#onconflict


2024年更新:现在有

em.upsert()
em.upsertMany()

https://mikro-orm.io/docs/entity-manager#upsert

© www.soinside.com 2019 - 2024. All rights reserved.