/// <summary> /// <paramref name="reader"/>의 레코드 정보를 <paramref name="nameMap"/>를 통해 매핑을 수행하는데, 계속조건 (<paramref name="continuationCondition"/>) 이 만족할때까지만 수행한다. /// </summary> /// <typeparam name="T">대상 객체</typeparam> /// <param name="reader">IDataReader 객체</param> /// <param name="targetFactory">대상 객체 생성용 Factory</param> /// <param name="nameMap">DB 컬럼명- 클래스 속성명 매핑 정보</param> /// <param name="continuationCondition">진행 조건 (False가 나올 때까지 진행합니다)</param> /// <param name="additionalMapping">컬럼-속성 단순 값 매핑 이외에 부가적인 매핑을 수행하기 위해 제공되는 델리게이트</param> /// <returns>매핑된 대상 객체 컬렉션</returns> public static IEnumerable <T> MapWhile <T>(this IDataReader reader, Func <T> targetFactory, INameMap nameMap, Func <IDataReader, bool> continuationCondition, Action <IDataReader, T> additionalMapping = null) { targetFactory.ShouldNotBeNull("targetFactory"); nameMap.ShouldNotBeNull("nameMap"); var columNames = nameMap.Keys.ToArray(); var targetAccessor = GetDynamicAccessor <T>(); Func <IDataReader, T> @readerMapFunc = dr => { var target = targetFactory(); columNames.RunEach(colName => targetAccessor.SetPropertyValue(target, nameMap[colName], dr.AsValue(colName))); if (additionalMapping != null) { additionalMapping(dr, target); } return(target); }; return(MapWhile(reader, readerMapFunc, continuationCondition)); }
/// <summary> /// <see cref="ConvertAll{TEntity}(IDataReader,INameMap)"/>와는 반대로, /// Persistent Object의 속성정보를 DbCommand Parameter Value로 설정한다. /// </summary> /// <param name="db">instance of <see cref="Database"/> defined in DAAB</param> /// <param name="cmd">instance of DbCommand</param> /// <param name="entity">Command로 실행할 Persistent object</param> /// <param name="nameMaps">DbCommand 인자명 : Persistent Object 속성명의 매핑 정보</param> /// <param name="ignoreCase">컬럼명과 속성명의 대소문자 구분없이 매칭합니다.</param> public static void SetParameterValues <T>(this Database db, DbCommand cmd, T entity, INameMap nameMaps, bool ignoreCase = true) { cmd.ShouldNotBeNull("cmd"); entity.ShouldNotBeNull("entity"); nameMaps.ShouldNotBeNull("nameMaps"); var accessor = DynamicAccessorFactory.CreateDynamicAccessor <T>(true); var propertyNames = accessor.GetPropertyNames(); if (IsDebugEnabled) { log.Debug("대상 Entity의 속성명 정보=[{0}]", propertyNames.CollectionToString()); } var parameters = new List <IAdoParameter>(); foreach (string paramName in nameMaps.Keys) { // remove parameter prefix var pName = paramName.RemoveParameterPrefix(); var propertyName = propertyNames.FirstOrDefault(pn => pn.EqualTo(nameMaps[pName], ignoreCase)); if (propertyName.IsNotWhiteSpace()) { parameters.Add(new AdoParameter(pName, accessor.GetPropertyValue(entity, propertyName))); } } SetParameterValues(db, cmd, parameters.ToArray()); }
/// <summary> /// 비동기적으로 ExecuteReader()을 수행하고, 병렬 방식으로 매핑하여 결과를 IPageList{T} 으로 반환하는 Task를 빌드합니다 /// </summary> /// <typeparam name="T">결과 셋으로 표현할 엔티티의 수형</typeparam> /// <param name="repository"><see cref="IAdoRepository"/></param> /// <param name="nameMap">DataReader 컬럼명 - Class 속성명의 매핑 정보</param> /// <param name="targetFactory">대상 객체 생성 Factory</param> /// <param name="additionalMapping">추가적인 매핑 함수</param> /// <param name="query">실행할 SQL문 또는 Procedure Name</param> /// <param name="pageIndex">결과셋의 Page Index (0부터 시작)</param> /// <param name="pageSize">결과셋 Paging 시의 Page Size</param> /// <param name="parameters">패러미터</param> /// <returns>매핑한 엔티티 컬렉션을 결과값으로 가지는 Task</returns> public static Task <IPagingList <T> > ExecuteInstanceAsParallelAsync <T>(this IAdoRepository repository, INameMap nameMap, Func <T> targetFactory, Action <AdoResultRow, T> additionalMapping, string query, int pageIndex, int pageSize, params IAdoParameter[] parameters) { nameMap.ShouldNotBeNull("nameMap"); targetFactory.ShouldNotBeNull("targetFactory"); query.ShouldNotBeWhiteSpace("query"); if (IsDebugEnabled) { log.Debug("비동기적으로 ExecuteReader()을 수행하고, 병렬 방식으로 매핑하여 결과를 IPageList<{0}>으로 반환하는 Task를 빌드합니다... " + @"query=[{1}]", typeof(T).Name, query); } var itemsTask = Task.Factory.StartNew(() => { using (var reader = repository.ExecuteReader(query, parameters)) return(reader.MapAsParallel <T>(targetFactory, nameMap, pageIndex * pageSize, pageSize, additionalMapping)); }); var totalItemCountTask = repository.CountAsync(query, parameters); var result = new PagingList <T>(itemsTask.Result, pageIndex, pageSize, totalItemCountTask.Result); return(Task.Factory.FromResult((IPagingList <T>)result)); }
/// <summary> /// <see cref="ExecuteInstance{T}(IAdoRepository,System.Func{System.Data.IDataReader,T},DbCommand,int,int,IAdoParameter[])"/>을 비동기적으로 수행합니다. /// </summary> /// <typeparam name="T">결과 셋으로 표현할 엔티티의 수형</typeparam> /// <param name="repository"><see cref="IAdoRepository"/></param> /// <param name="nameMap">DataReader 컬럼명 - Class 속성명의 매핑 정보</param> /// <param name="additionalMapping">추가적인 매핑 함수</param> /// <param name="query">실행할 SQL문 또는 Procedure Name</param> /// <param name="pageIndex">결과셋의 Page Index (0부터 시작)</param> /// <param name="pageSize">결과셋 Paging 시의 Page Size</param> /// <param name="parameters">패러미터</param> /// <returns>매핑한 엔티티 컬렉션을 결과값으로 가지는 Task</returns> public static Task <IPagingList <T> > ExecuteInstanceAsync <T>(this IAdoRepository repository, INameMap nameMap, Action <IDataReader, T> additionalMapping, string query, int pageIndex, int pageSize, params IAdoParameter[] parameters) where T : class { nameMap.ShouldNotBeNull("nameMap"); query.ShouldNotBeWhiteSpace("query"); if (IsDebugEnabled) { log.Debug("비동기적으로 ExecuteReader<{0}>()을 수행하고, 결과를 IList<{0}>으로 매핑합니다... query=[{1}]", typeof(T).FullName, query); } return(Task.Factory.StartNew(() => { using (var cmd = repository.GetCommand(query)) return repository.ExecuteInstance <T>(nameMap, additionalMapping, cmd, pageIndex, pageSize, parameters); })); }
/// <summary> /// 쿼리를 수행하여, 결과 셋을 대상 객체 컬렉션으로 병렬로 매핑을 수행하여 반환하는 Task를 빌드합니다. /// </summary> /// <typeparam name="T">결과 셋으로 표현할 엔티티의 수형</typeparam> /// <param name="repository"><see cref="IAdoRepository"/></param> /// <param name="nameMap">DataReader 컬럼명 - Class 속성명의 매핑 정보</param> /// <param name="targetFactory">대상 객체 생성 함수</param> /// <param name="firstResult">첫번째 레코드 인덱스 (0부터 시작)</param> /// <param name="maxResults">최대 레코드 갯수(0이면 끝까지)</param> /// <param name="additionalMapping">추가적인 매핑 함수</param> /// <param name="query">실행할 SQL문 또는 Procedure Name</param> /// <param name="parameters">패러미터</param> /// <returns>매핑한 엔티티 컬렉션을 결과값으로 가지는 Task</returns> public static Task <IList <T> > ExecuteInstanceAsParallelAsync <T>(this IAdoRepository repository, INameMap nameMap, Func <T> targetFactory, int firstResult, int maxResults, Action <AdoResultRow, T> additionalMapping, string query, params IAdoParameter[] parameters) { nameMap.ShouldNotBeNull("nameMap"); query.ShouldNotBeWhiteSpace("query"); if (IsDebugEnabled) { log.Debug("비동기적으로 ExecuteReader()을 수행하고, 병렬로 매핑하여 결과를 IList<{0}>으로 매핑합니다... " + "query=[{1}], firstResult=[{2}], maxResults=[{3}]", typeof(T).FullName, query, firstResult, maxResults); } return (Task.Factory .StartNew(() => { using (var reader = repository.ExecuteReader(query, parameters)) return reader.MapAsParallel <T>(targetFactory, nameMap, firstResult, maxResults, additionalMapping); })); }
//! ====================================================================================== /// <summary> /// 지정된 Entity의 속성 값을 이용하여 Procedure의 Parameter 값을 설정하고, 실행시키는 작업을 비동기적으로 수행합니다. /// 일반적으로 Save / Update시에 활용하면 좋다. /// 단, 비동기적인 작업이므로, Transaction 에 문제가 발생할 소지가 있습니다. /// </summary> /// <typeparam name="T">Persistent object 수형</typeparam> /// <param name="repository">IAdoRepository 인스턴스</param> /// <param name="spName">수행할 Procedure 명</param> /// <param name="entity">Persistent object</param> /// <param name="nameMap">ParameterName of Procedure = Property Name of Persistent object</param> /// <returns>Command 인자 중에 ParameterDirection이 ReturnValue인 인자의 값</returns> public static Task <object> ExecuteEntityTask <T>(this IAdoRepository repository, string spName, T entity, INameMap nameMap) { spName.ShouldNotBeWhiteSpace("spName"); entity.ShouldNotBeNull("entity"); nameMap.ShouldNotBeNull("nameMap"); return(Task.Factory.StartNew(() => repository.ExecuteEntity <T>(spName, entity, nameMap))); }
/// <summary> /// IDataReader 정보를 병렬 방식으로 매핑을 수행하여, 컬렉션을 반환합니다. /// </summary> /// <typeparam name="T">매핑 대상 수형</typeparam> /// <param name="reader">DataReader</param> /// <param name="nameMap">컬럼명-속성명 매핑 정보</param> /// <param name="targetFactory">대상 수형 Factory 함수</param> /// <param name="firstResult">첫번째 레코드 인덱스 (0부터 시작합니다. null이면 0으로 간주)</param> /// <param name="maxResults">매핑할 최대 레코드 수 (0이면, IDataReader의 끝까지 매핑합니다)</param> /// <param name="additionalMapping">추가 매핑 작업을 수행할 델리게이트</param> /// <returns>매핑된 객체의 컬렉션</returns> public static IList <T> MapAsParallel <T>(this IDataReader reader, Func <T> targetFactory, INameMap nameMap, int firstResult = 0, int maxResults = 0, Action <AdoResultRow, T> additionalMapping = null) { reader.ShouldNotBeNull("reader"); nameMap.ShouldNotBeNull("nameMap"); targetFactory.ShouldNotBeNull("targetFactory"); Guard.Assert(reader.IsClosed == false, "IDataReader가 이미 닫혀있습니다!!!"); if (IsDebugEnabled) { log.Debug("IDataReader를 읽어 수형[{0}]으로 병렬로 매핑하여, 컬렉션으로 반환합니다...", typeof(T).Name); } if (nameMap.Count == 0) { return(new List <T>()); } var resultSet = new AdoResultSet(reader, firstResult, maxResults); if (resultSet.Count == 0) { return(new List <T>()); } var targetAccessor = GetDynamicAccessor <T>(); var fieldNames = resultSet.FieldNames.Where(n => nameMap.ContainsKey(n)).ToArray(); return (resultSet.Values .AsParallel() .AsOrdered() .Select(row => { var target = targetFactory(); fieldNames.RunEach(fn => targetAccessor.SetPropertyValue(target, nameMap[fn], row[fn])); if (additionalMapping != null) { additionalMapping(row, target); } return target; }) .ToList()); }
/// <summary> /// <see cref="IAdoRepository.ExecuteInstance{T}(System.Func{System.Data.IDataReader,T},System.Data.Common.DbCommand,NFramework.Data.IAdoParameter[])"/> 를 비동기적으로 수행하여, /// DataReader로부터 <paramref name="filter"/> 에 만족하는 레코드만 T 수형의 인스턴스를 매핑한다. /// </summary> /// <typeparam name="T">결과 셋으로 표현할 엔티티의 수형</typeparam> /// <param name="repository"><see cref="IAdoRepository"/></param> /// <param name="targetFactory">대상 객체 생성용 Factory</param> /// <param name="nameMap">DB 컬럼명- 클래스 속성명 매핑 정보</param> /// <param name="filter">매핑할 Row를 선별할 필터 함수</param> /// <param name="query">실행할 SQL문 또는 Procedure Name</param> /// <param name="parameters">패러미터</param> /// <returns>매핑한 엔티티 컬렉션을 결과값으로 가지는 Task</returns> public static Task <IEnumerable <T> > ExecuteInstanceIfAsync <T>(this IAdoRepository repository, Func <T> targetFactory, INameMap nameMap, Func <IDataReader, bool> filter, string query, params IAdoParameter[] parameters) where T : class { nameMap.ShouldNotBeNull("nameMap"); filter.ShouldNotBeNull("filter"); return(Task.Factory.StartNew(() => { using (var reader = repository.ExecuteReader(query, parameters)) return reader.MapIf <T>(targetFactory, nameMap, filter, null); })); }
/// <summary> /// 지정된 Entity의 속성 값을 이용하여 Command의 Parameter 값을 설정하고, 실행시킨다. /// 일반적으로 Save / Update시에 활용하면 좋다. /// </summary> /// <typeparam name="T">Persistent object 수형</typeparam> /// <param name="repository">IAdoRepository 인스턴스</param> /// <param name="cmd">수행할 Command 객체</param> /// <param name="entity">처리할 Persistent object</param> /// <param name="nameMaps">ParameterName of Procedure = Property Name of Persistent object 매핑 정보</param> /// <returns>Command 인자 중에 ParameterDirection이 ReturnValue인 인자의 값</returns> public static object ExecuteEntity <T>(this IAdoRepository repository, DbCommand cmd, T entity, INameMap nameMaps) { cmd.ShouldNotBeNull("cmd"); entity.ShouldNotBeNull("entity"); nameMaps.ShouldNotBeNull("nameMap"); if (IsDebugEnabled) { log.Debug("Entity를 처리를 수행합니다. CommandText=[{0}], entity=[{1}], nameMaps=[{2}]", cmd.CommandText, entity.ObjectToString(), nameMaps.DictionaryToString()); } AdoTool.SetParameterValues(repository.Db, cmd, entity, nameMaps); return(repository.ExecuteCommand(cmd)); }
/// <summary> /// Execute DbCommand, Build instance of specified type by mapping DataReader Column Value to Instance Property Value /// </summary> /// <typeparam name="T">Type of Persistent object</typeparam> /// <param name="repository">IAdoRepository 인스턴스</param> /// <param name="nameMap">Key = ColumnName of DataReader, Value = Property Name of Specifieid Type</param> /// <param name="cmd">Instance of DbCommand to executed</param> /// <param name="parameters">Command parameters</param> /// <returns>Collection of Persistent object</returns> public static IList <T> ExecuteInstance <T>(this IAdoRepository repository, INameMap nameMap, DbCommand cmd, params IAdoParameter[] parameters) where T : class { nameMap.ShouldNotBeNull("nameMap"); cmd.ShouldNotBeNull("cmd"); if (IsDebugEnabled) { log.Debug("DataReader를 INameMap를 통해 지정된 Class의 인스턴스들을 생성합니다. " + "persistent=[{0}], nameMap=[{1}], commandText=[{2}], parameters=[{3}]", typeof(T).FullName, nameMap.DictionaryToString(), cmd.CommandText, parameters.CollectionToString()); } using (var reader = repository.ExecuteReader(cmd, parameters)) return(reader.Map <T>(ActivatorTool.CreateInstance <T>, nameMap)); }
/// <summary> /// <see cref="IAdoRepository.ExecuteInstance{T}(System.Func{System.Data.IDataReader,T},System.Data.Common.DbCommand,NFramework.Data.IAdoParameter[])"/> 를 비동기적으로 수행하여, /// <paramref name="continuationCondition"/> 조건이 만족할 동안만, DataReader로부터 T 수형의 인스턴스를 매핑한다. /// </summary> /// <typeparam name="T">결과 셋으로 표현할 엔티티의 수형</typeparam> /// <param name="repository"><see cref="IAdoRepository"/></param> /// <param name="targetFactory">대상 객체 생성용 Factory</param> /// <param name="nameMap">DB 컬럼명- 클래스 속성명 매핑 정보</param> /// <param name="continuationCondition">매핑을 계속할 조건인지 판단하는 델리게이트</param> /// <param name="query">실행할 SQL문 또는 Procedure Name</param> /// <param name="parameters">패러미터</param> /// <returns>매핑한 엔티티 컬렉션을 결과값으로 가지는 Task</returns> public static Task <IEnumerable <T> > ExecuteInstanceWhileAsync <T>(this IAdoRepository repository, Func <T> targetFactory, INameMap nameMap, Func <IDataReader, bool> continuationCondition, string query, params IAdoParameter[] parameters) where T : class { nameMap.ShouldNotBeNull("nameMap"); continuationCondition.ShouldNotBeNull("continuationCondition"); return(Task.Factory.StartNew(() => { using (var reader = repository.ExecuteReader(query, parameters)) return reader.MapWhile <T>(ActivatorTool.CreateInstance <T>, nameMap, continuationCondition, null); })); }
/// <summary> /// 지정된 Command를 실행하여, 결과 셋을 Paging하여, 지정된 Page에 해당하는 정보만 Persistent Object로 빌드하여 반환한다. /// </summary> /// <typeparam name="T">Persistent Object의 수형</typeparam> /// <param name="repository">IAdoRepository 인스턴스</param> /// <param name="nameMap">컬럼명:속성명의 매핑정보</param> /// <param name="additionalMapping">추가적인 매핑 함수</param> /// <param name="cmd">실행할 DbCommand</param> /// <param name="pageIndex">결과셋의 Page Index (0부터 시작)</param> /// <param name="pageSize">결과셋 Paging 시의 Page Size</param> /// <param name="parameters">DbCommand 실행시의 Parameter 정보</param> /// <returns>Paging된 Persistent Object의 List</returns> public static IPagingList <T> ExecuteInstance <T>(this IAdoRepository repository, INameMap nameMap, Action <IDataReader, T> additionalMapping, DbCommand cmd, int pageIndex, int pageSize, params IAdoParameter[] parameters) where T : class { nameMap.ShouldNotBeNull("nameMap"); cmd.ShouldNotBeNull("cmd"); if (IsDebugEnabled) { log.Debug("ExecuteReader를 수행해 PersistentObject로 매핑합니다... " + "CommandText=[{0}], NameMapping=[{1}], pageIndex=[{2}], pageSize=[{3}], parameters=[{4}]", cmd.CommandText, nameMap, pageIndex, pageSize, parameters.CollectionToString()); } var query = cmd.CommandText; var firstResult = pageIndex * pageSize; var maxResults = pageSize; var totalItemCountTask = repository.CountAsync(query, parameters); IList <T> instances; using (var dr = repository.ExecuteReader(cmd, parameters)) instances = dr.Map <T>(ActivatorTool.CreateInstance <T>, nameMap, firstResult, maxResults, additionalMapping); var pagingList = new PagingList <T>(instances, pageIndex, pageSize, totalItemCountTask.Result); if (IsDebugEnabled) { log.Debug("ExecuteReader를 수행해 PersistentObject로 매핑했습니다!!! pageIndex=[{0}], pageSize=[{1}], totalItemCount=[{2}]", pageIndex, pageSize, totalItemCountTask.Result); } return(pagingList); }
/// <summary> /// 생성자 /// </summary> /// <param name="nameMap"></param> public NameMapMapper(INameMap nameMap) { nameMap.ShouldNotBeNull("nameMap"); NameMap = nameMap; }
/// <summary> /// 지정된 IDataReader로부터 (컬럼명-속성명) 매핑 정보(<paramref name="nameMap"/>) 에 따라, 대상 객체를 인스턴싱하고, 속성에 값을 설정하여 반환합니다. /// </summary> /// <typeparam name="T">대상 객체의 수형</typeparam> /// <param name="reader">DataReader 객체</param> /// <param name="targetFactory">대상 객체 생성용 Factory</param> /// <param name="nameMap">DB 컬럼명- 클래스 속성명 매핑 정보</param> /// <param name="firstResult">첫번째 레코드 인덱스 (0부터 시작합니다. null이면 0으로 간주)</param> /// <param name="maxResults">매핑할 최대 레코드 수 (0이면, IDataReader의 끝까지 매핑합니다)</param> /// <param name="additionalMapping">컬럼-속성 단순 값 매핑 이외에 부가적인 매핑을 수행하기 위해 제공되는 델리게이트</param> /// <returns>매핑된 대상 객체의 컬렉션</returns> public static IList <T> Map <T>(this IDataReader reader, Func <T> targetFactory, INameMap nameMap, int firstResult, int maxResults, Action <IDataReader, T> additionalMapping) { reader.ShouldNotBeNull("reader"); nameMap.ShouldNotBeNull("nameMap"); targetFactory.ShouldNotBeNull("targetFactory"); Guard.Assert(reader.IsClosed == false, "지정된 IDataReader가 이미 닫혀 있습니다!!!"); if (IsDebugEnabled) { log.Debug("IDataReader를 읽어 INameMap을 이용하여 [{0}] 형식의 인스턴스 컬렉션을 반환합니다. " + "nameMap=[{1}], firstResult=[{2}], maxResults=[{3}]", typeof(T).FullName, nameMap.CollectionToString(), firstResult, maxResults); } var targets = new List <T>(); var firstIndex = firstResult; var maxCount = maxResults; while (firstIndex-- > 0) { if (reader.Read() == false) { return(targets); } } if (maxCount <= 0) { maxCount = Int32.MaxValue; } var targetAccessor = GetDynamicAccessor <T>(); var mappedCount = 0; var columNames = nameMap.Keys.ToArray(); while (reader.Read() && (mappedCount < maxCount)) { var target = targetFactory(); columNames.RunEach(colName => targetAccessor.SetPropertyValue(target, nameMap[colName], reader.AsValue(colName))); if (additionalMapping != null) { additionalMapping(reader, target); } targets.Add(target); mappedCount++; } if (IsDebugEnabled) { log.Debug("IDataReader로부터 [{0}] 수형의 인스턴스 [{1}]개를 생성했습니다.", typeof(T).FullName, targets.Count); } return(targets); }