2008-10-17 8 views
14

가능한 한 단순화하려고 시도한 시스템에 시나리오가 있습니다. 우리는 테이블을 가지고 (인공 지능이라고 부름) 인공물을 여러 가지 보안 역할로 액세스 할 수 있으며 보안 역할은 여러 인공물에 액세스 할 수 있습니다. 따라서 데이터베이스에는 3 개의 테이블이 있습니다. 하나는 인위적인 것을 설명하고 하나는 역할을 설명하고 하나는 인공 지능 ID를 역할 ID에 연결하는 다 대다 연관 테이블입니다.Many to Many Hibernate의 캐스케이드 삭제

우리는 두 가지 클래스를 가지고 있습니다. 하나는 역할을위한 것이고 하나는 인공물을위한 것입니다. artefact 클래스에는 액세스 할 수있는 역할 목록을 반환하는 IList 속성이 있습니다. (그러나 역할은 액세스 할 수있는 인공물을 얻는 속성을 제공하지 않습니다.)

이와 같이, 인공물에 대한 nhibernate 매핑에는 다음이 포함됩니다.

<bag name="AccessRoles" table="ArtefactAccess" order-by="RoleID" 
    lazy="true" access="field.camelcase-underscore" optimistic-lock="false"> 
    <key column="ArtefactID"/> 
    <many-to-many class="Role" column="RoleID"/> 
</bag> 

이 모두 잘 작동하고 내가 인공물을 삭제하면 연관 테이블은 적절하게 정리되고 제거 된 유물과 역할 사이의 모든 참조는 역할은 제대로하지만 삭제되지 않습니다 (제거 - 우리 돈으로 고아가 삭제되기를 원하지 않음).

문제는 - 역할을 삭제하고 자동으로 연결 테이블을 지우는 방법입니다. 현재 역할을 삭제하려고하면 역할에 대한 연결 테이블에 항목이 있으므로 참조 제약 조건이 생깁니다. 역할을 성공적으로 삭제할 수있는 유일한 방법은 해당 역할에 링크 된 모든 인공물을 쿼리하고 인공물의 역할 컬렉션에서 역할을 제거하고 인공물을 업데이트 한 다음 역할을 삭제하는 것입니다. 단순화 된 시스템에서 역할은 다른 테이블/오브젝트의 수에 관계 될 수 있습니다.

역할을 삭제할 때마다이 연관 테이블을 지우고 싶다는 NHibernate에 힌트를 드릴 수 있어야합니다. 가능하면 가능합니다. 그렇다면 어떻게해야합니까?

도움 주셔서 감사합니다.

답변

8

나는이 대답을 찾고 있었기 때문에 나는이 해결책을 게시하겠다고 생각했다. 3 개의 테이블 : Role, RolesToAccess (ManyToMany), Access.

는 다음 매핑을 만듭니다 액세스 :

<bag name="Roles" table="RolesToAccess" cascade="none" lazy="false"> 
     <key column="AccessId" /> 
     <many-to-many column="AccessId" class="Domain.Compound,Domain" /> 
    </bag> 

<bag name="RolesToAccess" cascade="save-update" inverse="true" lazy="false"> 
     <key column="AccessId" on-delete="cascade" /> 
     <one-to-many class="Domain.RolesToAccess,Domain" /> 
    </bag> 

역할 :

가 모델을 오염시키지 않도록 당신이 RolesToAccess 속성을 보호 할 수 있습니다 위에서 언급 한 바와 같이
<bag name="Accesses" table="RolesToAccess" cascade="none" lazy="false"> 
     <key column="RoleId" /> 
     <many-to-many column="RoleId" class="Domain.Compound,Domain" /> 
    </bag> 

<bag name="RolesToAccess" cascade="save-update" inverse="true" lazy="false"> 
     <key column="RoleId" on-delete="cascade" /> 
     <one-to-many class="Domain.RolesToAccess,Domain" /> 
    </bag> 

.

+1

안녕하세요, 솔루션에서 Role, RolesToAccess 및 Access의 세 가지 클래스를 만들어야합니까? 역할과 액세스의 두 클래스 만있는 솔루션을 알고 있습니까? –

0

연관 테이블에 대한 매핑을 만든 다음 Role_id가 삭제하려는 값인 해당 테이블에서 delete를 호출 한 다음 역할 자체의 삭제를 수행 할 수 있습니다. 이것을하기 위해서는 상당히 간단해야합니다.

+0

도메인 테이블에 연관 테이블을 나타내지는 않을 것이고, 이는 NHibernate를 사용하는 코드에서 연관 테이블에 대해 수동으로 삭제하는 유일한 방법 일 것입니다. –

0

NHibernate는 C# 클래스 롤에 컬렉션이 없어도이를 수행 할 수있는 방법을 제공해야한다고 생각하지만 SQL에서는이 동작을 항상 설정할 수 있습니다. 데이터베이스의 FK에 대해 계단식 삭제를 선택하면 NHib의 캐시에주의를 기울여야합니다.

하지만 마지막 리소스로 사용하는 것이 좋습니다.

0

역할에서 Artifact으로 매핑을 만들어야합니다.

게으른 로딩을하고 보호 된 가상 멤버에 맵핑하여 실제로 액세스하지 못하게 할 수 있지만 NHibernate가 ArtefactAccess 테이블에서 롤을 삭제해야한다는 것을 알기 위해서는 해당 맵핑이 필요합니다

+0

David, 역할 -> 이슈 매핑을 추가해도 연관 데이터가 자동으로 삭제되지 않으므로 해당 매핑의 반대가 데이터를 소유합니다. 즉, 이슈에서 역할을 제거하거나 이슈를 삭제하면 연관 테이블이 정리됩니다. 다른 방법으로. 따라서 매핑을 추가하면 역할이있는 모든 아티팩트를 다시 찾아야하며 아티팩트를 다시 저장하고 (연결 테이블 정리) 역할을 제거해야합니다. 이는 나에게 효율적이지 않습니다. –

1

당신은 여기 뭐라고 :

성공적으로 역할을 삭제하는 유일한 방법은, 그 역할에 링크 모든 유물에 대한 쿼리 유물의 역할 컬렉션에서 역할을 제거, 유물을 업데이트 한 다음 삭제하는 것입니다 매우 단순하지 않은 시스템에서 역할이 다른 테이블/개체와 관련 될 수있는 경우 특히 그 역할은 그리 효율적이지 않거나 훌륭합니다.

필요하지 않습니다. 연관 테이블을 매핑 (도메인 객체로 만들기)하고 싶지 않다고 가정하면 최소한의 코드로 양쪽 끝에서 삭제를 수행 할 수 있습니다.

Role, Artifact 및 ArtifactAccess (링크 테이블) 테이블이 3 개 있다고 가정 해 봅시다. 매핑에서 Role과 Artifact에 대한 도메인 개체 만 있습니다. 둘 다 many-many 협회를위한 가방을 가지고 있습니다.

역할 :

<bag name="Artifacts" table="[ArtifactAccess]" schema="[Dbo]" lazy="true" 
     inverse="false" cascade="none" generic="true"> 
     <key column="[ArtifactID]"/> 

     <many-to-many column="[RoleID]" class="Role" /> 
    </bag> 

아티팩트 :

<bag name="Roles" table="[ArtifactAccess]" schema="[Dbo]" lazy="true" 
     inverse="false" cascade="none" generic="true"> 
     <key column="[RoleID]"/> 

     <many-to-many column="[ArtifactID]" class="Role" /> 
    </bag> 

당신이 볼 수 있듯이, 양쪽 끝이 지정된 역 = false를 가지고있다. NHibernate 문서에서는 협회의 한 쪽 끝을 'inverse'끝으로 선택하는 것을 권장하지만, 둘 다 '통제 끝'으로 사용하는 것을 멈추게 할 것은 없습니다. 업데이트 또는 삽입을 수행 할 때, 이것은 두 방향에서 장애없이 작동합니다. 양쪽 끝 중 하나를 삭제할 때 연결 테이블이 업데이트되지 않기 때문에 FK 위반 오류가 발생합니다. 하지만 삭제를 수행하기 전에 컬렉션을 다른 쪽 끝으로 지우는 것만으로이를 해결할 수 있습니다.이 작업은 사용자가 수행하는 작업보다 훨씬 덜 복잡합니다. 'this'의 사용이있는 경우 연결의 '기타'끝에 있습니다. 끝. 조금 혼란 스럽다면 여기에 코드 예제가 있습니다. 당신은 단지 제어 한쪽 끝이있는 경우, 복잡한을 위해 당신이 할 필요가 삭제 : 어떤 역할을 삭제할 때 내가 할 것은

roleToDelete.Artifacts.Clear(); //removes the association record 
roleToDelete.Delete(); // removes the artifact record 

그것은 하나 개의 코드 추가 라인의 같은이

foreach(var artifact in role.Artifacts) 
    foreach(var role in artifact.Roles) 
     if(role == roleToDelete) 
      artifact.Roles.Remove(role) 
    artifact.Save(); 
roleToDelete.Delete(); 

하지만, 이 방법을 사용하면 연관의 어느 쪽이 반대인지 결정할 필요가 없습니다. 또한 전체 제어를 위해 연결 테이블을 매핑 할 필요가 없습니다.

+0

둘 모두를 제어용으로 사용할 때 NHibernate는 관계를 두 번 삽입하려고 시도합니다. 나는 통제 측을 다른쪽으로 바꾸어서이 문제를 해결했다. –