문제

다음과 같은 매핑이 있습니다.

<set name="People" lazy="true" table="ProjectPeople">
  <key column="ProjectId" />
  <composite-element class="PersonRole">
    <many-to-one name="Person" column="PersonId" cascade="save-update" not-null="true" />
    <many-to-one name="Role" column="RoleId" cascade="save-update" not-null="true"  />
  </composite-element>
</set>

이제 도메인의 역할에 대한 별도의 클래스를 갖고 싶지 않고 역할 이름만 필요합니다.그러나 DB 역할에서는 여전히 별도의 테이블로 정규화되어야 합니다. Role (Id, Name).

사람들이 다음 PersonRole 클래스를 사용하도록 어떻게 매핑합니까?

public class PersonRole {
    public virtual Person Person { get; set; }
    public virtual string Role { get; set; }
}

업데이트:현상금이 추가되었습니다. 나뿐만 아니라 유용한 질문인 것 같습니다.

도움이 되었습니까?

해결책

개인적으로 나는 Yassir와 같은 역할 클래스를 만들 것입니다

그러나 현재 가지고있는 구조를 사용하려면 Person Tesp에 대한 Foriegn 키와 역할 설명이 포함 된보기를 만듭니다.

새보기를 가리 키도록 세트 매핑 테이블을 수정 한 다음 역할 매핑을 수정하여 많은 ~ 하나의 매핑 대신 속성이되도록하십시오.

그러나이 접근법을 취하면 견해를 다시 시작하기 때문에 역할을 업데이트 할 수 없다는 것을 의미합니다.

편집하다: 추가 할 수있는 역할을 업데이트하려면 <sql-insert>,<sql-update> and <sql-delete> Cascade-All이 작동하도록 매핑 파일에

다른 팁

실제로는 불가능하기 때문에 원하는 답을 얻지 못할 것입니다.(N)Hibernate는 객체-관계-매핑 프레임워크이자 지원입니다. 세 가지 종류의 매핑 전략:

  • 클래스 계층별 테이블
  • 하위 클래스별 테이블
  • 구체적인 클래스별 테이블

또한 다음을 사용하여 이로부터 벗어날 수 있습니다. formula 또는 sql-insert 등, 그러나 당신이 발견한 바와 같이, 이것들은 결국 당신에게 더 많은 고통을 야기할 뿐이며, Hibernate 커뮤니티에서는 권장되지 않으며 코드의 유지 관리에 좋지 않습니다.

해결책?

실제로는 매우 간단합니다.다음 용도로 클래스를 사용하고 싶지 않습니다. Role.나는 당신이 원하지 않는다는 뜻이라고 생각합니다 폭로하다 Role 유형의 클래스이며 입력할 필요가 없는 클래스 prObject.Role.Name 항상.단지 prObject.Role, 문자열을 반환해야 합니다.여러 가지 옵션이 있습니다:

  1. PersonRole과 같은 내부 클래스를 사용하세요. 이 클래스는 내부 클래스이거나 비공개 클래스일 수 있습니다.구성원 필드를 설정하고 업데이트하는 역할 속성을 추가합니다.
  2. 내부 클래스를 사용하십시오.구성원 필드를 설정하고 업데이트하는 역할 속성을 추가합니다.

옵션 2를 살펴보겠습니다.

// mapped to table Role, will not be visible to users of your DAL
// class can't be private, it's on namespace level, it can when it's an inner class
internal class Role 
{
    // typical mapping, need not be internal/protected when class is internal
    // cannot be private, because then virtual is not possible
    internal virtual int Id { get; private set; }
    internal virtual string Name { get; set; }
}

// the composite element
public class PersonRole
{
    // mapped properties public
    public virtual Person Person { get; set; }

    // mapped properties hidden
    internal virtual Role dbRole { get; set; }

    // not mapped, but convenience property in your DAL
    // for clarity, it is actually better to rename to something like RoleName
    public string Role     /* need not be virtual, but can be */
    { 
        get
        {
            return this.dbRole.Name;
        }
        set
        {
            this.dbRole.Name = value;    /* this works and triggers the cascade */
        }
    }
}

그리고 매핑은 예상대로 보일 수 있습니다.결과:클래스당 하나의 테이블 규칙(편집하다:질문자는 명시적으로 해당 규칙을 위반하고 싶어하며 Hib이 이를 지지한다고 말합니다. 이는 맞습니다.) 그러나 일반적인 객체 지향 기술을 사용하여 객체를 수정 및 액세스하지 못하도록 숨겼습니다.모든 NH 기능(캐스케이드 등)은 여전히 ​​예상대로 작동합니다.

(N) Hibernate는 다음과 같은 유형의 결정에 관한 것입니다.명확성, 간결성 또는 유지 관리성을 희생하거나 OO 또는 ORM 규칙을 위반하지 않고 데이터베이스에 대해 신중하고 안전한 추상화 계층을 만드는 방법.


업데이트(q.문을 닫았음)

이러한 유형의 문제를 처리할 때 제가 많이 사용하는 다른 훌륭한 접근 방식은 다음과 같습니다.

  • 매핑을 정상적으로 생성하고(예: 테이블당 하나의 클래스, 마음에 들지 않지만 최선의 방법임) 확장 메서드를 사용합니다.

     // trivial general example
     public static string GetFullName(this Person p)
     {
         return String.Format("{0} {1}", p.FirstName, p.LastName);
     }
    
     // gettor / settor for role.name
     public static string GetRoleName(this PersonRole pr)
     {
         return pr.Role == null ? "" : pr.Role.Name;
     }
     public static SetRoleName(this PersonRole pr, string name)
     {
         pr.Role = (pr.Role ?? new Role());
         pr.Role.Name = name;
     }
    
  • 일반적으로 매핑을 생성하되 다음을 사용하십시오. partial class이를 통해 원하는 방식으로 수업을 "장식"할 수 있습니다.장점:생성된 테이블 매핑을 사용하는 경우 원하는 만큼 자주 다시 생성할 수 있습니다.물론 부분 클래스는 별도의 파일에 저장되어야 하므로 "부풀림"을 줄이려는 의도를 고려하면 현재로서는 좋은 시나리오가 아닐 수 있습니다.

     public partial class PersonRole
     {
         public string Role {...}
     }
    
  • 아마도 가장 간단할 것입니다:그냥 과부하 ToString() ~을 위한 Role, 이는 다음에 사용하기에 적합합니다. String.Format 물론 친구와도 할당할 수는 없습니다.기본적으로 각 엔터티 클래스 또는 POCO에는 ToString() 어쨌든 과부하.

NHibernate를 사용하여 직접적으로 이를 수행하는 것이 가능하지만, q.내가 그것을 볼 시간이 생기기 전에 닫혔습니다(누구 잘못도 아니고 시간이 없었을 뿐입니다).접근 방식에 동의하지 않더라도 Hibernate HBM 매핑을 통해 이를 수행할 시간이 있으면 업데이트하겠습니다.최종 결과가 다른 프로그래머에게 덜 명확하고 전체적으로 덜 명확할 때(그 테이블은 어디로 갔습니까?) Hib의 고급 개념을 가지고 씨름하는 것은 좋지 않습니다.왜 해당 테이블에 대한 IDao 추상화가 없나요?또한보십시오 NHibernate 모범 사례 그리고 S#arp).하지만 그럼에도 불구하고 운동은 흥미롭다.

"모범 사례"에 대한 의견을 고려하면 다음과 같습니다.일반적인 상황에서는 "테이블당 하나의 클래스"만이 아니라 각 테이블마다 하나의 IDaoXXX, 하나의 DaoConcreteXXX 및 하나의 GetDaoXXX가 있어야 합니다. 여기서 클래스/인터페이스 계층 구조를 사용하여 읽기 전용 테이블과 읽기/쓰기 테이블을 구별합니다.이는 테이블당 최소 4개의 클래스/코드 줄입니다.이는 일반적으로 자동 생성되지만 데이터 계층(dal)에 매우 명확한 액세스 계층(dao)을 제공합니다.데이터 레이어는 가능한 한 간소하게 유지하는 것이 가장 좋습니다.이러한 "모범 사례" 중 어떤 것도 이동을 위해 확장 방법이나 부분 방법을 사용하는 것을 방해하지 않습니다. Role.Name ~ 안으로 Role.

이것들이 최고야 일반적인 관행.특정 특수하거나 일반적인 상황에서는 항상 가능하거나 실행 가능하거나 필요한 것은 아닙니다.

나는 내가 당신이라면 원시 유형에 다중 하나를 맵핑 할 수 없다고 생각합니다.

이것은 전체 순수 주의적 일 중 가장 큰 끄기입니다. 확실히 목표는 작업 응용 프로그램을 갖는 것입니다. 완벽한 클래스 계층 구조의 일부 버전이 아닙니다. 따라서 "pupject.role"대신 "pupject.role.name"을 코딩 해야하는 경우 어떻게해야합니까? 이것이 더 나은 신뢰할 수있는 프로그램을 만드는 데 어떻게 도움이됩니까?

애플리케이션 디자인 순수한 관점에서 당신이 원하는 것은 평범한 잘못입니다. 사람은 몇 가지 역할을 수행 할 수 있으며, 일반적으로 여러 사람에게 역할을 할 수 있습니다. 왜이 모든 문제로 가서 개인당 데이터 모델이 1 인당 많은 역할을 할 때, 1 인당 비현실적인 하나의 역할 Hierachy를 시행 하는가?

실제로 "사람 당 하나의 역할"규칙이있는 경우 기본 데이터 모델에 반사되어야합니다.

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