2013-01-14 4 views
1

나는 수정을 요청받은 레거시 데이터베이스 (DB2)에서 작동하는 NHibernate 구현을 가지고 있으며 id 생성기가 id 속성에서 작동하도록하는 문제에 직면 해있다. 고객 사용자 유형으로 정의됩니다. 테이블의사용자 정의 사용자 타입을 가진 NHibernate ID 생성기

데이터는 다음과 같은 클래스에 매핑 :

// CLASS FILE 
public class Request { 
    public virtual int Id { get; set; } 
    ... other data properties ... 
} 

//MAPPING FILE 
<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="LibraryName" namespace="LibraryName.Domain" default-cascade="none"> 
    <class name="Request" schema="..." table="..." where="..."> 
     <id name="Id" column="..." type="LibraryName.Domain.DB2UserTypes.NullableIntegerType, LibraryName" /> 

     ... other data property mappings ... 


레거시 데이터베이스는 요청의 테이블에 외래 키입니다 열이있는 테이블이 있습니다. 이러한 외래 키가 들어있는 열은 nullable이 아니므로 요청 개체 속성이 참조 개체에서 null 인 경우 사용자 지정 NullableIntegerType을 사용하여 외래 키 열에 0을 쓸 수 있습니다. 우리는 새로운 요청 객체를 생성하고 ID는 발전기를 사용하여 생성 할 수 있도록

// NullableIntegerType Definition 
public class NullableIntegerType : IEnhancedUserType 
{ 
    private static readonly SqlType[] SQL_TYPES = { NHibernate.NHibernateUtil.Int32.SqlType }; 
    public SqlType[] SqlTypes { get { return SQL_TYPES; } } 

    public new bool Equals(object x, object y) 
    { 
     if (object.ReferenceEquals(x, y)) 
      return true; 
     else if ((x == null) && (y == null)) 
      return true; 
     else if ((x == null) || (y == null)) 
      return false; 
     else 
      return x.Equals(y); 
    } 

    public object DeepCopy(object value) { return value; } 
    public bool IsMutable { get { return false; } } 
    public object Assemble(object cached, object owner) { return cached; } 
    public object Disassemble(object value) { return value; } 
    public object Replace(object original, object target, object owner) { return original; } 
    public int GetHashCode(object obj) { return obj.GetHashCode(); } 

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

    public object NullSafeGet(IDataReader dr, string[] names, object owner) 
    { 
     object obj = NHibernate.NHibernateUtil.Int32.NullSafeGet(dr, names[0]); 
     if (obj == null) 
      return null; 
     else 
     { 
      int result = (int)obj; 

      if ((result == 0) || (result == 9999999)) 
       return null; 
      else 
      { 
       return int.Parse(result.ToString()); 
      } 
     } 
    } 

    public void NullSafeSet(IDbCommand cmd, object obj, int index) 
    { 
     if (obj == null) 
      NHibernateUtil.Int32.NullSafeSet(cmd, 0, index); 
     else 
      NHibernateUtil.Int32.NullSafeSet(cmd, obj, index); 
    } 

    public object FromXMLString(string xml) 
    { 
     return int.Parse(xml); 
    } 

    public string ToXMLString(object obj) 
    { 
     return ((int)obj).ToString(); 
    } 

    public string ObjectToSQLString(object obj) 
    { 
     return ((int)obj).ToString(); 
    } 
} 


나는 매핑을 수정하도록 요청하고있다. 생성자 클래스를 생성하고 생성자를 사용하기 위해 요청 개체 매핑을 수정했습니다.

// GENERATOR CLASS 
public class RequestGenerator : TableGenerator 
{ 
    public override object Generate(NHibernate.Engine.ISessionImplementor session, object obj) 
    { 
     using (IDbCommand command = session.Connection.CreateCommand()) 
     { 
      command.CommandText = @"..."; 
      command.CommandType = CommandType.StoredProcedure; 

      var parameter = command.CreateParameter(); 
      parameter.DbType = DbType.Int32; 
      parameter.ParameterName = "@generatedId"; 
      parameter.Value = 0; 
      parameter.Direction = ParameterDirection.InputOutput; 
      command.Parameters.Add(parameter); 

      command.ExecuteNonQuery(); 

      return Convert.ToInt32(parameter.Value); 
     } 
    } 
} 

//MODIFIED MAPPING FILE 
<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="LibraryName" namespace="LibraryName.Domain" default-cascade="none"> 
    <class name="Request" schema="..." table="..." where="..."> 
     <id name="Id" column="..." type="LibraryName.Domain.DB2UserTypes.NullableIntegerType, LibraryName" > 
      <generator class="LibraryName.Domain.DB2Generators.RequestGenerator, LibraryName" /> 
     </id> 

     ... other data property mappings ... 


나는 내 코드 전에 오류가 수정 된 매핑을 테스트하려고

도 NHibernate에이 ID 생성기를 초기화 할 수 없음을 실행합니다. 나는 ID 매핑에서 사용자 정의 유형 (유형 = "LibraryName.Domain.DB2UserTypes.NullableIntegerType,하여 LibraryName")을 제거하면

// Sample Code 
Request request = new Request() { Id = 0, ... other properties } 
session.Save(request); 
session.Flush(); 

// Exception Details and Stack Trace 
NHibernate.MappingException was unhandled by user code 
Message=could not instantiate id generator: LibraryName.Domain.DB2Generators.RequestGenerator, LibraryName 
Source=NHibernate 
StackTrace: 
    at NHibernate.Id.IdentifierGeneratorFactory.Create(String strategy, IType type, IDictionary`2 parms, Dialect dialect) 
    at NHibernate.Mapping.SimpleValue.CreateIdentifierGenerator(Dialect dialect, String defaultCatalog, String defaultSchema, RootClass rootClass) 
    at NHibernate.Impl.SessionFactoryImpl..ctor(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners) 
    at NHibernate.Cfg.Configuration.BuildSessionFactory() 
    at LibraryName.Infrastructure.NH.NHibernateSessionFactory.createSessionFactory() in C:\...\NHibernate\NHibernateSessionFactory.cs:line 23 
    at LibraryName.Infrastructure.NH.NHibernateSessionFactory.get_SessionFactory() in C:\...\NHibernate\NHibernateSessionFactory.cs:line 15 
    at LibraryName.Infrastructure.NH.NHibernateSessionFactoryProvider.CreateInstance(IContext context) in C:\...\NHibernate\NHibernateSessionFactoryProvider.cs:line 13 
    at Ninject.Activation.Provider`1.Create(IContext context) 
    at Ninject.Activation.Context.Resolve() 
    at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) 
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
    at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext() 
    at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source) 
    at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters) 
    at LibraryName.Infrastructure.InternalMvcModule.<Load>b__0(IContext c) in C:\...\Ninject\InternalMvcModule.cs:line 16 
    at Ninject.Activation.Providers.CallbackProvider`1.CreateInstance(IContext context) 
    at Ninject.Activation.Provider`1.Create(IContext context) 
    at Ninject.Activation.Context.Resolve() 
    at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) 
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
    at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source) 
    at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent) 
    at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) 
    at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) 
    at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target) 
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() 
    at System.Linq.Buffer`1..ctor(IEnumerable`1 source) 
    at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) 
    at Ninject.Activation.Providers.StandardProvider.Create(IContext context) 
    at Ninject.Activation.Context.Resolve() 
    at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) 
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
    at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source) 
    at Ninject.Web.Mvc.NinjectDependencyResolver.GetService(Type serviceType) 
    at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) 


    InnerException: System.ArgumentException 
    Message=type is not a ValueTypeType 
    Parameter name: type 
    Source=NHibernate 
    ParamName=type 
    StackTrace: 
     at NHibernate.Id.TableGenerator.Configure(IType type, IDictionary`2 parms, Dialect dialect) 
     at NHibernate.Id.IdentifierGeneratorFactory.Create(String strategy, IType type, IDictionary`2 parms, Dialect dialect) 
     InnerException: 

는 발전기가 제대로 작동하고 내 개체는 데이터베이스에 저장합니다. 생성자와 사용자 정의 유형이 함께 작동하도록하려면 어떻게해야합니까?

답변

1

NHibernate sources of the TableGenerator classConfigure 메서드에서 열 유형이 PrimitiveType의 하위 클래스 일 것으로 예상합니다. 귀하의 경우에는 이것이 실현되지 않을 것으로 보입니다. 왜냐하면 단순히 IEnhancedUserType을 구현하기 때문입니다 (내부적으로 랩핑 되겠지만, PrimitiveType이 아닌 무언가에 의해).

이유를 설명 할 수 없지만 내 프로젝트 중 하나에서 유사한 요구 사항, 즉 사용자 정의 NHibernate 유형에 0/null 마술을 구현하고 사용자 정의 ID 생성기를 사용하는 것과 마주하고 있습니다. 내 프로젝트에서 사용자 정의 "id"유형은 IUserType을 직접 구현하고 ID 생성기는 IIdentifierGeneratorIConfigurable을 직접 구현합니다. 즉, NHibernate의 TableGenerator을 확장하지 않습니다. 어쩌면 당신은 귀하의 id 생성기와 NHibernate의 TableGenerator의 열 유형 제한을 해결하기 위해해야합니다.

+0

감사합니다. 나는 확장하려고하는 클래스 라이브러리를 처음 설계 한 개발자가'IEnhancedUserType'을 구현하여 클래스에 저장되지 않은 값 속성이있는 id 매핑과 함께 사용할 수 있다고 믿습니다. 직접 인터페이스를 구현하고 테스트 해 보겠습니다. –

관련 문제