2013-02-01 7 views
1

우리 사무실 팀은 .NET Framework 4 및 NHibernate 3.3.1을 사용하는 ASP.NET 프로젝트를 사용합니다.Hibernate가 Database uniqueidentifier 필드에 대해 NULL로 저장되도록 System.Guid.Empty의 값을 가진 C# POCO Guid 속성을 "변환"하도록 하시겠습니까?

AllResourcesInfo라는 POCO 도메인 클래스가 있습니다 (궁극적으로 내부 데이터베이스에있는 리소스 테이블에 매핑 됨) 다른 테이블에서는 AllResourcesInfo가 Resource 테이블에 매핑된다고 가정 해 보겠습니다.

은 또한 아마도 부서와 대일 관계를 가질 수있다 (궁극적으로 데이터베이스에 부서 테이블에 매핑) 부서라는 마시고 도메인 클래스

AllResourcesInfo 있습니다.

AllResourcesInfo의 인스턴스가 부서에 속하면 AllResourcesInfo.DepartmentDatabaseID에 Department 엔터티에있는 유효한 DepartmentDatabaseID가 있습니다.

그러나 AllResourcesInfo의 인스턴스가 부서에 속하지 않으면 AllResourcesInfo.DepartmentDatabaseID의 datbase에 NULL 값이 있습니다. 데이터 베이스. 내가 NHibernate에가 (기본적으로 NHibernate에이 데이터베이스에 읽기를 수행) AllResourcesInfo 테이블에서 값을 검색하는 데 사용할 때

, NHibernate에이 00000000-0000-0000-0000-000000000000 값 AllResourcesInfo.DepartmentDatabaseID의 C# POCO 속성을 채 웁니다 (즉, AllResourcesInfo가 부서에 소속되어 있지 않은 경우 System.Guid.Empty 값)

그러나 어떤 부서에도 속하지 않는 AllResourcesInfo의 새로운 C# POCO 인스턴스를 저장하기 위해 NHibernate Session을 사용하면 POCO 00000000-0000-0000-0000-000000000000 값 (예 : System.Guid.Empty 값)을 가진 AllResourcesInfo.DepartmentDatabaseID의 속성 그러나 데이터베이스는 분명히 오류를 발생시킵니다. Guid 값 00000000-0000-0000-0000-000000000000 o 분명히 데이터베이스의 부서 테이블에 존재하지 않습니다.

요약하면, NHibernate Session Save는 uniqueidentifier 필드 값을 null로 남겨두기를 원할 때 NULL 값을 사용하여 Database의 uniqueidentifier 필드를 저장 (또는 떠나기)에 실패합니다.

혹시 NHibernate가 System.Guid.Empty 값으로 C# POCO Guid 속성을 "변환"하여 데이터베이스 uniqueidentifier 필드 값에 대해 NULL로 저장 (또는 왼쪽)하도록 보장 할 수 있습니까?

+0

. 그러나 nullable Guid를 사용하는 대신 아무것도 표시하지 않기 위해 Guid.Empty를 사용해야하는 이유가 있습니까? – Rich

답변

3

NHibernate의 IUserType을 구현해야합니다.

그것은이를 좋아한다 :

using NHibernate.SqlTypes; 
using NHibernate.UserTypes; 

[Serializable] //to allow NH configuration serialization 
public class GuidTypeConverter : IUserType 
{ 
    SqlType[] sqlTypes; 

    public GuidTypeConverter() 
    { 
     sqlTypes = new[] { SqlTypeFactory.GetSqlType(DbType.Guid, 0, 0) }; 
    } 

    public SqlType[] SqlTypes 
    { 
     get { return sqlTypes; } 
    } 

    public Type ReturnedType 
    { 
     get { return typeof(Guid); } 
    } 

    public object NullSafeGet(IDataReader rs, string[] names, object owner) 
    { 
     if (rs[names[0]] == DBNull.Value) 
     { 
      return Guid.Empty; 
     } 

     return (Guid) rs[names[0]]; 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) 
    { 
     var param = (IDataParameter) cmd.Parameters[index]; 
     param.DbType = sqlTypes[0].DbType; 
     var guid = (Guid) value; 

     if (guid != Guid.Empty) 
     { 
      param.Value = guid;  
     } 
     else 
     { 
      param.Value = DBNull.Value; 
     } 
    } 

    public bool IsMutable 
    { 
     //guid is struct so it's not mutable 
     get { return false; } 
    } 

    public object DeepCopy(object value) 
    { 
     return value; 
    } 

    public object Replace(object original, object target, object owner) 
    { 
     return original; 
    } 

    public object Assemble(object cached, object owner) 
    { 
     return cached; 
    } 

    public object Disassemble(object value) 
    { 
     return value; 
    } 

    public new bool Equals(object x, object y) 
    { 
     return x != null && x.Equals(y); 
    } 

    public int GetHashCode(object x) 
    { 
     return x.GetHashCode(); 
    } 
} 

(캐스트가 여기에있다, 나는 그것을 테스트하지 않습니다 - 일부 조정이 아마 필요) 매핑에서

를 지정 :

<property name="GuidProperty" column="guidColumn" type="GuidTypeConverterNamespace.GuidTypeConverter, GuidTypeConverterAssemblyName" /> 
+2

이것은 매우 간단한 코드를 작성하는 것처럼 보입니다. 나는 NHibernate를 떠날 것이라고 생각한다. – tomfanning

+0

글쎄, 어쩌면 그럴지도 모르겠지만, 필자는 상용구 코드를 내 프로젝트 (ImmutableTypeConverter)의 기본 클래스로 포장한다. 나는 이것을 이유로 NHibernate를 벗어나는 이유를 찾지 못한다. "featurerichness"는 약간의 비용이 든다. – pkmiec

+0

@pkmiec 코드를 보내 주셔서 감사합니다. 나는 당신의 충고를 받아 들였지만, 탐파닝 (tomfanning)은 좋은 지적을 불러 일으킨 것 같습니다. 그것은 단순한 것을 위해 꽤 많은 일을합니다. – user1338998

3

Guid는 null 일 수 없습니다. null을 허용하기 위해 유형을 Nullable<Guid> 또는 짧게는 Guid?으로 변경할 수 있습니다.

+1

특히 System.Guid는 정수형 또는 double 형과 같은 구조체 또는 값 유형입니다. – tomfanning

+0

@tomfanning 죄송합니다. 잘못된 질문을 던졌습니다. 누군가가 Hibernate가 System.Guid.Empty의 값으로 C# POCO Guid 속성을 "변환"하여 데이터베이스 uniqueidentifier 필드 값에 대해 NULL로 저장 (또는 왼쪽)하도록 보장 할 수있는 방법을 말해 줄 수 있습니까? – user1338998

+0

@ user1338998 나왔습니다. 답변을 입력했습니다. – tomfanning

2

Guid (null이 아닌 GUID)와 데이터베이스의 GUID 간의 매핑을 만드는 것이 좋습니다. 이것은 NHibernate의 IUserType 인터페이스의 목적이다. 변환을 수행 한 다음 사용자 정의 GuidUserType 클래스가 필요하며 매핑 정의 (hbxml, fluent, whatever)에서이 클래스를 참조하십시오. 전체 설명은 http://blog.miraclespain.com/archive/2008/Mar-18.html을 참조하십시오.

0

Department 개체의 기본 키 매핑에 unsaved-value라는 속성이 있어야합니다. 그 값을 Guid.Empty의 값으로 설정하면 모두 괜찮을 것입니다.

이 다음은 원시 HBM 매핑을 사용하여 할 거라고 방법의 예입니다 : 당신의 매핑에 사용하기 위해 고객 IUserType 클래스를 개발하여 솔루션이 있습니다

<id name="DepartmentId" type="Guid" unsaved-value="00000000-0000-0000-0000-000000000000"> 
    <generator class="guid" /> 
</id>