在调用
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 中现在有更新插入功能:
你不能,你有责任在上下文(身份映射)中拥有有效的状态。您应该使用 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()
。