Skip to main content
Version: 6.4

级联持久化、合并和删除

从 v4.2 开始,级联合并不再可配置(并且对所有关系保持启用状态)。

¥From v4.2, cascade merging is no longer configurable (and is kept enabled for all relations).

本节介绍应用级级联。为了实现这一点,我们需要填充关系。

¥This section is about application level cascading. For that to work, we need to have relations populated.

在持久化或删除实体时,默认情况下,所有引用都是级联持久化的。这意味着通过持久化任何实体,ORM 将自动持久化其所有关联。

¥When persisting or removing entity, all your references are by default cascade persisted. This means that by persisting any entity, ORM will automatically persist all of its associations.

你可以通过 @ManyToOne@ManyToMany@OneToMany@OneToOne 字段的 cascade 属性来控制此行为。

¥You can control this behaviour via cascade attribute of @ManyToOne, @ManyToMany, @OneToMany and @OneToOne fields.

没有主键的新实体将始终保留,无论 cascade 值如何。

¥New entities without a primary key will always be persisted, regardless of cascade value.

// cascade persist is default value
@OneToMany({ entity: () => Book, mappedBy: 'author' })
books = new Collection<Book>(this);

// same as previous definition
@OneToMany({ entity: () => Book, mappedBy: 'author', cascade: [Cascade.PERSIST] })
books = new Collection<Book>(this);

// only cascade remove
@OneToMany({ entity: () => Book, mappedBy: 'author', cascade: [Cascade.REMOVE] })
books = new Collection<Book>(this);

// no cascade
@OneToMany({ entity: () => Book, mappedBy: 'author', cascade: [] })
books = new Collection<Book>(this);

// cascade all (persist and remove)
@OneToMany({ entity: () => Book, mappedBy: 'author', cascade: [Cascade.ALL] })
books = new Collection<Book>(this);

// same as previous definition
@OneToMany({ entity: () => Book, mappedBy: 'author', cascade: [Cascade.PERSIST, Cascade.REMOVE] })
books = new Collection<Book>(this);

级联持久化

¥Cascade persist

以下是级联持久化如何工作的示例:

¥Here is example of how cascade persist works:

const book = await orm.em.findOne(Book, 'id', { populate: ['author', 'tags'] });
book.author.name = 'Foo Bar';
book.tags[0].name = 'new name 1';
book.tags[1].name = 'new name 2';
await orm.em.persist(book).flush(); // all book tags and author will be persisted too

当级联持久化集合时,请记住只有完全初始化的集合才会级联持久化。

¥When cascade persisting collections, keep in mind only fully initialized collections will be cascade persisted.

级联删除

¥Cascade remove

级联删除的工作方式与级联持久相同,只是用于删除实体。以下示例假定 Book.publisher 设置为 Cascade.REMOVE

¥Cascade remove works same way as cascade persist, just for removing entities. Following example assumes that Book.publisher is set to Cascade.REMOVE:

请注意,集合的级联删除效率低下,因为它将为集合中的每个实体触发 1 个查询。

¥Note that cascade remove for collections can be inefficient as it will fire 1 query for each entity in collection.

await orm.em.remove(book).flush(); // this will also remove book.publisher

请记住,在 @ManyToOne 字段上使用级联删除可能会很危险,因为级联删除的实体可以在未被删除的另一个实体中保持引用。

¥Keep in mind that cascade remove can be dangerous when used on @ManyToOne fields, as cascade removed entity can stay referenced in another entities that were not removed.

const publisher = new Publisher(...);
// all books with same publisher
book1.publisher = book2.publisher = book3.publisher = publisher;
await orm.em.remove(book1).flush(); // this will remove book1 and its publisher

// but we still have reference to removed publisher here
console.log(book2.publisher, book3.publisher);

孤立删除

¥Orphan removal

除了 Cascade.REMOVE 之外,还有额外的、更积极的移除级联模式,可以使用 @OneToOne@OneToMany 属性的 orphanRemoval 标志来指定:

¥In addition to Cascade.REMOVE, there is also additional and more aggressive remove cascading mode which can be specified using the orphanRemoval flag of the @OneToOne and @OneToMany properties:

@Entity()
export class Author {

@OneToMany({ entity: () => Book, mappedBy: 'author', orphanRemoval: true })
books = new Collection<Book>(this);

}

orphanRemoval 标志的行为与删除操作的 Cascade.REMOVE 相同,因此同时指定两者是多余的。

¥orphanRemoval flag behaves just like Cascade.REMOVE for remove operation, so specifying both is redundant.

使用简单的 Cascade.REMOVE,你需要删除 Author 实体以将操作级联到所有已加载的 Book。通过在集合上启用孤立删除,当 Book 与集合断开连接时(通过 remove() 或通过 set() 替换集合项),它们也将被删除:

¥With simple Cascade.REMOVE, you would need to remove the Author entity to cascade the operation down to all loaded Books. By enabling orphan removal on the collection, Books will be also removed when they get disconnected from the collection (either via remove(), or by replacing collection items via set()):

await author.books.set([book1, book2]); // replace whole collection
await author.books.remove(book1); // remove book from collection
await orm.em.persist(author).flush(); // book1 will be removed, as well as all original items (before we called `set()`)

在此示例中,由于没有执行删除操作,因此不会使用简单的 Cascade.REMOVE 删除任何 Book

¥In this example, no Book would be removed with simple Cascade.REMOVE as no remove operation was executed.

声明式引用完整性

¥Declarative Referential Integrity

这仅在 SQL 驱动程序中受支持。

¥This is only supported in SQL drivers.

cascade 选项控制的应用级级联相反,我们还可以定义数据库级引用完整性操作:on updateon delete

¥As opposed to the application level cascading controlled by the cascade option, we can also define database level referential integrity actions: on update and on delete.

它们的值是从 cascade 选项值自动推断出来的。你还可以通过 updateRuledeleteRule 选项手动控制值。

¥Their values are automatically inferred from the cascade option value. You can also control the value manually via updateRule and deleteRule options.

@Entity()
export class Book {

@ManyToOne({ updateRule: 'set null', deleteRule: 'cascade' })
author?: Author;

}