(업데이트 아래 참조)유창함 NHibernate에 :와 문제 다 대다 사용자 정의 중개 테이블과의 관계
그래서, 내가 (우리가 전화 할게를 ClassA와 ClassB가) 두 개체가 전시 많은이 (ClassA는 여러 개의 ClassB 객체를 가질 수 있으며 그 반대도 가능함).
전통적인 "many-to-many"보다는 실제로 "관계"자체가 다른 두 클래스 (관계 시작 날짜, 관계 이름 등) 간의 연결에 대한 다른 정보를 가진 객체입니다.
ClassA와 ClassB 사이에 many-to-many로 정의하지 않고, 세 번째 중개 클래스에서 가리키는 두 개의 일대 다 관계 (ClassA와 ClassB 중 하나)를 정의했습니다 '관계'라고 부름). 구조적으로, 나는이처럼 보이도록 테이블을 기대 :
ClassA Relationship
---------------- ----------------
Id (PK) Id (PK)
Name Name
Description StartDate
ClassA_Id (FK)
ClassB ClassB_Id (FK)
----------------
Id (PK)
Name
Description
는이를 달성하기 위해, 그래서 같이 매핑을 설정 (시행 착오의 톤 후) :
public ClassAMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Relationship)
.KeyColumn("ClassA_Id")
.ForeignKeyConstraintName("FK_Relationship_ClassA")
.LazyLoad()
.Cascade.All()
.Inverse();
}
public ClassBMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Relationship)
.KeyColumn("ClassB_Id")
.ForeignKeyConstraintName("FK_Relationship_ClassB")
.LazyLoad()
.Cascade.All()
.Inverse();
}
public RelationshipMap()
{
Id(x => x.Id);
Map(x => x.CreatedDate);
References(x => x.ClassAObject)
.Column("ClassA_Id")
.Cascade.SaveUpdate();
References(x => x.ClassBObject)
.Column("ClassB_Id")
.Cascade.SaveUpdate();
}
이제 상위 개체를 추가/삭제할 때 그의 개체는 예상대로 정확하게 작동합니다. 예를 들어, 새로운 ClassA와 ClassB를 생성하고 관계를 연결 한 다음 ClassA를 저장하면 관련된 모든 레코드가 세 개의 테이블에 추가됩니다. 마찬가지로 동일한 ClassA를 제거하면 ClassA 레코드와 관계 레코드는 제거되지만 ClassB 레코드는 남아 있습니다 (예상되는 동작). 하지만, 난 그냥 부모 개체 중 하나 (예 : classA.Relationships.Remove(relationshipObject); classARepository.Update(classA);
)에서 관계를 제거하려고하면
후 나는 다음과 같은 오류를 얻을 : 또한
NHibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [ClassB]
NHibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations) [Relationship#9]
, 데이터베이스에서 ClassA 개체를 완전히 다시로드하고 위에서 설명한대로 멤버 자격을 제거하면 오류없이 실행되지만 관계는 데이터베이스에서 제거되지 않습니다.
찾고있는 동작을 달성하기 위해 매핑을 어떻게 변경할 수 있습니까?
- 를 ClassA/B/관계가 추가 된
- 기록 관계 새로운를 ClassA를 추가
- 제거 업데이트 : 참고로
, 여기에 통과해야 시나리오의 개요입니다 기존 ClassA- ClassA 및 관계에 대한 레코드가 삭제되었습니다.
- ClassB 레코드가 테이블에 남아 있습니다.
- ClassA에서 관계를 제거하십시오.관계 목록; : @ JamieIde의 답변에 따라, 나는 다음과 같은 조정을 내놓았다 : 이
를 ClassA와 ClassB가 기록
UPDATE 남아 관계 테이블에서를 ClassA
- 제거 관계를 업데이트
- 관계에 대한 ClassA 및 ClassB에 대한 참조를 제외합니다.
Cascade.AllDeleteOrphan()
로를 ClassA/ClassB가에// NOTE, this is an example snippet to show the steps that need to be taken using(var session = SomeSessionFactory().OpenSession()) { using (var transaction = session.BeginTransaction()) { // preferably place these four lines in a public method on one of the objects classAObject.Relationships.Remove(relationship); classBObject.Relationships.Remove(relationship); relationship.ClassA = null; relationship.ClassB = null; transaction.Commit(); } }
- 변경
.Cascade.All()
. 이것은 당신은 매핑을 변경할 필요가 없습니다
public ClassAMap() { Id(x => x.Id); Map(x => x.Name); HasMany(x => x.Relationship) .KeyColumn("ClassA_Id") .ForeignKeyConstraintName("FK_Relationship_ClassA") .LazyLoad() .Cascade.AllDeleteOrphan() // here's the key line .Inverse(); }
+1, 이것은 옳은 길에 나에게 확실히 도착했다. 부모 객체를 null로 만드는 것만으로 NHibernate가 빈을 삽입하도록 만들었 기 때문에 부모 객체의'Cascade.All()'을'Cascade.AllDeleteOrphan()'으로 변경해야했다. ClassA/ClassB 테이블에 레코드가 있습니다. 또한, 명시 적으로 update (나는 NHibertate에 익숙하지 않습니다.)를 호출하지 않고 개체의 변경 사항이 선택된다는 것을 인식하지 못했습니다. 작업 코드로 내 질문을 업데이트 할 것입니다. – valverij