레거시 DB를 다룰 때 NHibernate에서 다대일 관계를 모델링하는 가장 좋은 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/10915

  •  08-06-2019
  •  | 
  •  

문제

경고 - 저는 NHibernate를 처음 접했습니다.저는 이 질문이 단순해 보인다는 것을 알고 있습니다. 그리고 간단한 대답이 있을 것이라고 확신합니다. 하지만 저는 이 질문에 대해 한동안 헤매었습니다.구조적으로 실제로 변경할 수 없는 레거시 DB를 다루고 있습니다.고객이 수락한 지불 계획을 나열하는 세부정보 테이블이 있습니다.각 지불 계획에는 계획의 이용 약관 등을 얻기 위해 참조 테이블로 다시 연결되는 ID가 있습니다.내 개체 모델에는 AcceptedPlan 클래스와 Plan 클래스가 있습니다.원래 나는 NHibernate에서 이 관계를 모델링하기 위해 세부 테이블에서 다시 참조 테이블까지 다대일 관계를 사용했습니다.또한 Plan 클래스에서 AcceptedPlan 클래스로 반대 방향으로 진행되는 일대다 관계를 만들었습니다.단순히 데이터를 읽는 동안에는 괜찮았습니다.내 AcceptedPlan 클래스의 속성인 Plan 개체로 이동하여 계획의 세부 정보를 읽을 수 있었습니다.세부 정보 테이블에 새 행을 삽입해야 할 때 문제가 발생했습니다.내가 읽은 바에 따르면 새 하위 개체를 만드는 유일한 방법은 해당 개체를 상위 개체에 추가한 다음 세션을 저장하는 것입니다.하지만 새 세부 레코드를 생성할 때마다 새 상위 계획 개체를 생성할 필요는 없습니다.이는 불필요한 오버헤드처럼 보입니다.내가 이 문제를 잘못된 방식으로 진행하고 있는지 아는 사람이 있나요?

도움이 되었습니까?

해결책

나는 논리적인 부모를 포함하는 자식 개체를 갖는 것을 피하고 싶습니다. 그렇게 하면 매우 지저분해지고 매우 빠르게 재귀될 수 있습니다.그런 일을 하기 전에 도메인 모델을 어떻게 사용할 것인지 살펴보겠습니다.테이블에 ID 참조를 쉽게 유지하고 매핑되지 않은 상태로 둘 수 있습니다.

다음은 올바른 방향으로 여러분을 안내할 수 있는 두 가지 매핑 예입니다. 테이블 이름 등을 조정해야 했지만 도움이 될 수 있습니다.StatusId를 열거형에 매핑하는 것이 좋습니다.

가방이 세부 정보 테이블을 컬렉션에 효과적으로 매핑하는 방식에 주의하세요.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.Customer, Namespace" table="Customer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="CustomerAccountId" length="4" sql-type="int" not-null="true" unique="true" index="CustomerPK"/>
            <generator class="native" />
        </id>

        <bag name="AcceptedOffers" inverse="false" lazy="false" cascade="all-delete-orphan" table="details">
          <key column="CustomerAccountId" foreign-key="AcceptedOfferFK"/>
          <many-to-many
            class="Namespace.AcceptedOffer, Namespace"
            column="AcceptedOfferFK"
            foreign-key="AcceptedOfferID"
            lazy="false"
           />
        </bag>

  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.AcceptedOffer, Namespace" table="AcceptedOffer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="AcceptedOfferId" length="4" sql-type="int" not-null="true" unique="true" index="AcceptedOfferPK"/>
            <generator class="native" />
        </id>

        <many-to-one 
          name="Plan"
          class="Namespace.Plan, Namespace"
          lazy="false"
          cascade="save-update"
        >
        <column name="PlanFK" length="4" sql-type="int" not-null="false"/>
        </many-to-one>

        <property name="StatusId" type="Int32">
            <column name="StatusId" length="4" sql-type="int" not-null="true"/>
        </property>

  </class>
</hibernate-mapping>

다른 팁

제가 글을 쓰는 동안 귀하의 데이터베이스 다이어그램을 보지 못했습니다.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.Customer, Namespace" table="Customer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="customer_id" length="4" sql-type="int" not-null="true" unique="true" index="CustomerPK"/>
            <generator class="native" />
        </id>

        <bag name="AcceptedOffers" inverse="false" lazy="false" cascade="all-delete-orphan">
            <key column="accepted_offer_id"/>
            <one-to-many class="Namespace.AcceptedOffer, Namespace"/>
        </bag>

  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.AcceptedOffer, Namespace" table="Accepted_Offer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="accepted_offer_id" length="4" sql-type="int" not-null="true" unique="true" />
            <generator class="native" />
        </id>

        <many-to-one name="Plan" class="Namespace.Plan, Namespace" lazy="false" cascade="save-update">
            <column name="plan_id" length="4" sql-type="int" not-null="false"/>
        </many-to-one>

  </class>
</hibernate-mapping>

아마도 트릭을 수행해야 할 것입니다(컬렉션에 대한 예제 매핑만 수행했으므로 다른 속성을 추가해야 합니다).

이를 모델링하기 위해 내가 취하는 접근 방식은 다음과 같습니다.

고객 개체에는 고객이 수락한 계획을 나타내는 ICollection <PaymentPlan> PaymentPlan이 포함되어 있습니다.

고객에 대한 PaymentPlan은 세부 정보 테이블을 사용하여 어떤 고객 ID가 어떤 PaymentPlan에 매핑되는지 설정하는 가방을 사용하여 매핑됩니다.계단식 전체 삭제 고아를 사용하면 고객이 삭제된 경우 세부정보의 항목과 고객이 소유한 PaymentPlan이 모두 삭제됩니다.

PaymentPlan 개체에는 지불 계획의 조건을 나타내는 PlanTerms 개체가 포함되어 있습니다.

PlanTerms는 관련 PlanTerms 개체에 대한 참조를 PaymentPlan에 삽입하는 다대일 매핑 계단식 저장 업데이트를 사용하여 PaymentPlan에 매핑됩니다.

이 모델을 사용하면 PlanTerms를 독립적으로 생성한 다음 고객에게 새 PaymentPlan을 추가할 때 관련 PlanTerms 개체를 전달하는 새 PaymentPlan 개체를 만든 다음 관련 고객의 컬렉션에 추가할 수 있습니다.마지막으로 Customer를 저장하고 nhibernate가 저장 작업을 계단식으로 진행하도록 합니다.

특정 PlanTerms(계획 테이블)에 모두 부착된 PaymentPlans(세부 정보 테이블)의 인스턴스를 소유한 Customer(고객 테이블)가 있는 Customer 개체, PaymentPlan 개체 및 PlanTerms 개체가 생성됩니다.

필요한 경우 매핑 구문에 대한 좀 더 구체적인 예가 있지만 자신의 모델을 사용하여 작업하는 것이 가장 좋을 것이며 특정 예를 제공할 만큼 데이터베이스 테이블에 대한 정보가 충분하지 않습니다.

이것이 내 NHibernate 경험이 제한되어 있기 때문인지는 모르겠지만, Detail 테이블에 직접 매핑되는 Details에 대한 속성만 포함하는 BaseDetail 클래스를 생성할 수 있습니까?

그런 다음 추가 상위 계획 개체가 있는 BaseDetail 클래스에서 상속되는 두 번째 클래스를 만듭니다. 그러면 세부 행을 만들고 여기에 PlanId를 할당할 때 BaseDetail 클래스를 만들 수 있지만 전체 세부 정보를 채워야 하는 경우 상위 계획 객체와 함께 기록하면 상속된 Detail 클래스를 사용할 수 있습니다.

그게 말이 되는지 모르겠지만 알려주시면 더 자세히 설명하겠습니다.

여기서 문제는 AcceptedOffer 개체에 Plan 개체가 포함되어 있고 Plan 개체에 AcceptedOffer 개체가 포함된 AcceptedOffers 컬렉션이 포함된 것처럼 보인다는 것입니다.고객도 마찬가지입니다.개체가 서로의 자식이라는 사실이 문제의 원인이라고 생각합니다.

마찬가지로 AcceptedOffer를 복잡하게 만드는 것은 두 가지 책임이 있다는 것입니다.이는 계획에 포함된 제안을 나타내며 고객의 수락을 나타냅니다.이는 단일 책임 원칙을 위반하는 것입니다.

플랜에 포함된 제안과 고객이 수락한 제안을 구별해야 할 수도 있습니다.그래서 제가 할 일은 다음과 같습니다.

  1. 상태가 없는 별도의 Offer 객체를 만듭니다. 예를 들어 고객도 없고 상태도 없습니다. OfferId와 해당 속성이 속한 Plan만 있습니다.
  2. Offers 컬렉션을 갖도록 계획 개체를 수정합니다(해당 컨텍스트에서 제안을 수락할 필요는 없음).
  3. 마지막으로 제안, 고객 및 상태가 포함되도록 AcceptedOffer 개체를 수정합니다.고객은 동일하게 유지됩니다.

나는 이것이 NHibernate 매핑과 객체 저장 문제를 충분히 풀 것이라고 생각합니다.:)

NHibernate에 도움이 될 수도 있고 그렇지 않을 수도 있는 팁:마치 뷰가 테이블인 것처럼 뷰에 대해 객체를 매핑할 수 있습니다.뷰 이름을 테이블 이름으로 지정하기만 하면 됩니다.모든 NOT NULL 필드가 뷰와 매핑에 포함되어 있으면 제대로 작동합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top