# 삭제 규칙 모듈의 여러 엔티티 간 관계를 생성할 때, **레코드를 삭제**할 때 어떤 참조 무결성을 사용할지 정의해야 합니다. **참조 무결성**은 엔티티 A의 레코드가 삭제되었을 때 해당 엔티티 A의 레코드를 참조하고 있는 엔티티 B의 레코드가 어떻게 될지를 지정합니다. 아래 엔티티 다이어그램은 Customer(주 엔티티 A)와 Order(관련 엔티티 B)의 관계를 정의하고 있습니다. Customer는 여러 개의 Order를 가질 수 있으며, Order는 하나의 Customer에만 속합니다. [참조 속성](https://success.outsystems.com/ja-jp/documentation/11/building_apps/data_management/data_modeling/entity_relationships/)(데이터베이스 용어로는 외래 키에 해당)은 엔티티 **Order**의 속성 **CustomerId**입니다. ![Customer(엔티티 A)와 CustomerId 참조 속성을 가진 Order(엔티티 B)의 관계를 보여주는 다이어그램](https://success.outsystems.com/TK_Resource/6d54fe65-7cc4-41de-bbe5-686e24f759ba "Customers와 Orders의 엔티티 관계 다이어그램") 이 예시에서는 **참조 무결성**을 지정함으로써 Customer가 삭제되었을 때 Customer의 Order가 어떻게 될지 정의합니다. 두 엔티티 간 관계에서 **참조 무결성**을 지정하려면, 관련 엔티티의 **참조 속성**을 편집하고 **Delete Rule** 속성의 값을 `Protect`, `Delete`, `Ignore` 중 하나로 설정해야 합니다. ![Delete Rule 속성의 드롭다운 메뉴에 있는 Protect, Delete, Ignore 옵션 스크린샷](https://success.outsystems.com/TK_Resource/dc5a3ab4-86a3-4f5a-a8aa-9250db2d3a0b "참조 무결성 Delete Rule 옵션") **Protect** **Delete Rule**을 `Protect`로 설정하면, 관련 엔티티 내에 관련 레코드가 있는 경우 주 엔티티의 레코드는 삭제되지 않습니다. 이 동작은 참조 속성으로 생성된 데이터베이스 제약조건에 의해 보장됩니다. 관련 엔티티에 관련 레코드가 아직 있는 주 엔티티의 레코드를 삭제하려고 하면, Platform Server가 데이터베이스 예외를 반환하고 작업은 실행되지 않습니다. **Delete(삭제)** **Delete Rule**을 `Delete`로 설정한 경우, 주 엔티티의 레코드를 삭제하면 관련 엔티티 내의 관련 레코드도 모두 삭제됩니다. 이 메커니즘은 일반적으로 "계단식 삭제"로 알려져 있습니다. 이 동작은 참조 속성으로 생성된 데이터베이스 제약조건에 의해 보장됩니다. **Ignore** **Delete Rule**을 `Ignore`로 설정한 경우, 관련 엔티티 내의 관련 레코드를 유지한 채로 주 엔티티의 레코드를 삭제할 수 있습니다. `Ignore` 값에서는 참조 무결성이 보장되지 않으므로, 데이터베이스 제약조건이 발생하지 않습니다. 따라서 **Delete Rule** 속성의 값을 이전 값에서 `Ignore`로 변경한 경우, 해당 자동 인덱스는 삭제됩니다(속성 중 하나를 수동으로 변경한 경우 제외). 확장에 의해 공개된 외부 엔티티를 외부 키 속성이 참조하는 경우, 참조 무결성을 보장할 수 없으므로 사용 가능한 **Delete Rule** 속성의 값은 `Ignore`뿐입니다. 엔티티 모델을 설계할 때, 여러 관계의 Delete Rule을 적절히 설정하여 시스템이 각 사용 사례에서 예상대로 작동하도록 해야 합니다. 사용 사례에 따라 적절한 선택을 하는 데 도움이 되는 각 옵션의 예시와 고려사항을 아래에 제시합니다. ## 'Protect'의 예시 `Protect` 값은 최종 사용자가 애플리케이션 화면에서 직접 엔티티 데이터를 삭제할 수 있는 경우에 자주 사용됩니다. 다음과 같은 비즈니스 시나리오를 고려해 봅시다. - 최종 사용자가 **Customers**를 삭제할 수 있는 애플리케이션 화면이 있습니다. - **Customer**는 여러 개의 **Order**를 가질 수 있으며, **Order**는 하나의 **Customer**에만 속합니다. - 관련된 Order가 있는 경우, **Customer**를 삭제할 수 없습니다. 참조 속성 **CustomerId**의 **Delete Rule** 속성을 `Protect`로 설정하면, 최종 사용자는 관련 Order가 남아 있는 Customer를 삭제할 수 없습니다. ![Order 엔티티의 CustomerId 참조 속성의 Delete Rule을 Protect로 설정하는 예시](https://success.outsystems.com/TK_Resource/cc15d28c-72f7-491d-a3f5-1c4ea3e3c4c8 "Protect Delete Rule 예시") 관련 Order가 남아 있는 Customer를 삭제하려고 하면 데이터베이스 예외가 발생하고, 작업은 실행되지 않습니다. ![Protect 삭제 규칙을 사용하고 있을 때 관련 Order가 있는 Customer를 삭제하려고 할 때 표시되는 오류 메시지](https://success.outsystems.com/TK_Resource/fcd6ca3e-3a25-4803-8639-caf34d3ada77 "Protect Delete Rule에 대한 데이터베이스 예외") 이 경우, Customer를 삭제하려면 해당 Customer가 주문한 Order를 먼저 모두 삭제해야 합니다. 이 방법은 delete 문을 개별적으로 제어하고 최적화할 수 있으며, 데이터 무결성도 확보되므로 성능이 우수합니다. 더 높은 제어와 성능을 얻으려고 하면 구현 비용이 높아지므로, 둘 중 하나를 우선시해야 합니다. ### 장점 - 관련 엔티티에서 참조하고 있는 주 엔티티의 레코드는 삭제할 수 없으므로, 항상 데이터 모델의 무결성이 유지됩니다. ### 제약 - 로직 내에서 삭제 순서가 적절하도록 조정해야 합니다. 관련 엔티티의 레코드를 먼저 삭제한 다음에 주 엔티티의 레코드를 삭제해야 합니다. - 모델에 새 관련 엔티티를 추가할 때마다, 해당 관련 엔티티도 삭제 사이클 로직에 포함시켜야 합니다. ## 'Delete'의 예시 `Delete` 값은 데이터 제거 메커니즘을 구현할 때 모델 전체에 걸쳐 자동 계단식 삭제를 수행해야 하는 경우에 자주 사용됩니다. 일반적으로 데이터 제거 메커니즘은 비동기 프로세스(타이머 또는 BPT)에 의해 처리되므로, 성능에는 영향을 미치지 않습니다. 다음과 같은 비즈니스 시나리오를 고려해 봅시다. - 5년 이상 지난 종료된 **Order**를 모두 삭제합니다. - **Order**에는 **OrderItem**이 하나 이상 있고, **OrderItem**은 하나의 **Order**에만 속합니다. - **Order**가 삭제되었을 때, 관련된 **OrderItem**도 모두 삭제되어야 합니다. 참조 속성 **OrderId**의 **Delete Rule** 속성을 `Delete`로 설정하면, Order가 삭제되었을 때 관련된 OrderItem도 모두 자동으로 삭제됩니다. ![Delete Rule을 Delete로 설정하여 Order를 삭제하면 관련 OrderItem도 삭제되는 계단식 삭제 예시](https://success.outsystems.com/TK_Resource/3e889dda-16be-41af-afd2-c6359e2186c8 "Delete Rule을 사용한 계단식 삭제 예시") ### 장점 - 항상 데이터 모델의 무결성이 유지됩니다. 주 엔티티의 레코드를 삭제하면 관련 엔티티의 관련 레코드도 모두 삭제되므로, 관련 엔티티에서 레코드가 참조되지 않게 됩니다. - 주 엔티티 수준에서만 레코드를 삭제하면 되므로, 삭제 로직의 개발과 유지보수가 간단합니다. - 참조 속성의 **Delete Rule**을 `Delete`로 설정하기만 하면 되므로, 새로운 관련 엔티티를 모델에 추가할 때 개발 노력이 적게 듭니다. ### 제약 - 이 방법은 관련 레코드의 수에 따라 성능이 저하될 수 있습니다. 삭제 작업마다 관련 엔티티의 관련 레코드를 확인하기 때문에, delete 문의 실행에 시간이 걸립니다. 따라서 엔티티 모델이 복잡하고 성능이 중요한 경우(최종 사용자가 애플리케이션 화면에서 직접 엔티티 데이터를 삭제할 수 있는 경우 등), 이 방법은 권장되지 않습니다. ## 'Ignore'의 예시 Ignore 값은 기록 데이터 아카이브 메커니즘을 구현할 때, 주 엔티티의 레코드는 삭제하지만 주 레코드의 세부 정보가 관련되지 않음을 고려하여 관련 엔티티의 레코드를 모두 유지해야 하는 경우에 자주 사용됩니다. 다음과 같은 비즈니스 시나리오를 고려해 봅시다. - **Order**에 대해 수행된 모든 작업의 로그가 **OrderHistory**에 기록됩니다. - 하나의 **OrderHistory** 레코드는 하나의 **Order**에만 관련되고, 하나의 **Order**에는 관련된 **OrderHistory** 레코드가 하나 이상 있습니다. - 5년 이상 지난 종료된 **Order**를 모두 삭제합니다. 단, 컴플라이언스 상의 이유로 **OrderHistory** 레코드를 10년 동안 유지해야 합니다. 참조 속성 **OrderId**의 **Delete Rule** 속성을 `Ignore`로 설정함으로써, Order를 삭제하고 관련된 OrderHistory 레코드는 유지할 수 있습니다. ![Ignore 삭제 규칙을 사용하여 관련 OrderHistory 레코드를 유지한 채로 Order를 삭제하는 예시](https://success.outsystems.com/TK_Resource/4db004db-26cd-4f3f-a784-75e1efc97644 "기록 데이터 아카이빙을 위한 Ignore Delete Rule") ### 장점 - 관련 엔티티에 영향을 미치지 않고 주 엔티티의 레코드를 삭제할 수 있습니다. ### 제약 - 이 방법을 사용하면 데이터 모델이 불일치하게 됩니다. 관련 레코드는 유지되지만, 주 레코드의 세부 정보를 얻을 수 없고 식별자만 얻을 수 있게 됩니다. - 참조 속성의 **Delete Rule** 속성 값을 이전 값에서 `Ignore`로 변경한 경우, 해당 자동 인덱스는 삭제됩니다. 참조 속성을 쿼리 필터로 사용하는 경우, 새 인덱스를 수동으로 추가해야 합니다.