| 0 | 1 #region | 
|  | 2 | 
|  | 3 using System; | 
|  | 4 using System.Collections; | 
|  | 5 using System.Collections.Generic; | 
|  | 6 using System.Data; | 
|  | 7 using System.Linq; | 
|  | 8 using BLToolkit.Data; | 
|  | 9 using BLToolkit.Reflection.Extension; | 
|  | 10 | 
|  | 11 #endregion | 
|  | 12 | 
|  | 13 namespace BLToolkit.Mapping | 
|  | 14 { | 
|  | 15     public class FullMappingSchema : MappingSchema | 
|  | 16     { | 
|  | 17         #region Fields | 
|  | 18 | 
|  | 19         private readonly DbManager _db; | 
|  | 20         private readonly bool _ignoreLazyLoad; | 
|  | 21         private DataTable _schema; | 
|  | 22         private List<string> _schemaColumns; | 
|  | 23         private readonly MappingSchema _parentMappingSchema; | 
|  | 24         private readonly FactoryType _factoryType; | 
|  | 25 | 
|  | 26         private ExtensionList _extensions; | 
|  | 27 | 
|  | 28         #endregion | 
|  | 29 | 
|  | 30         public FullMappingSchema(DbManager db, bool ignoreLazyLoad = false, MappingSchema parentMappingSchema = null, | 
|  | 31             FactoryType factoryType = FactoryType.LazyLoading) | 
|  | 32         { | 
|  | 33             _db = db; | 
|  | 34             _parentMappingSchema = parentMappingSchema; | 
|  | 35             _factoryType = factoryType; | 
|  | 36             _ignoreLazyLoad = ignoreLazyLoad; | 
|  | 37         } | 
|  | 38 | 
|  | 39         #region Overrides | 
|  | 40 | 
|  | 41         public override ExtensionList Extensions | 
|  | 42         { | 
|  | 43             get | 
|  | 44             { | 
|  | 45                 if (_parentMappingSchema != null) | 
|  | 46                     return this._parentMappingSchema.Extensions; | 
|  | 47                 return _extensions; | 
|  | 48             } | 
|  | 49             set | 
|  | 50             { | 
|  | 51                 if (_parentMappingSchema != null) | 
|  | 52                     this._parentMappingSchema.Extensions = value; | 
|  | 53                 _extensions = value; | 
|  | 54             } | 
|  | 55         } | 
|  | 56 | 
|  | 57         protected override ObjectMapper CreateObjectMapperInstance(Type type) | 
|  | 58         { | 
|  | 59             return new FullObjectMapper(_db, _ignoreLazyLoad,_factoryType); | 
|  | 60         } | 
|  | 61 | 
|  | 62         protected override void MapInternal(Reflection.InitContext initContext, IMapDataSource source, object sourceObject, IMapDataDestination dest, object destObject, params object[] parameters) | 
|  | 63         { | 
|  | 64             FullObjectMapper mapper = (FullObjectMapper)initContext.ObjectMapper; | 
|  | 65             IDataReader dataReader = (IDataReader)sourceObject; | 
|  | 66 | 
|  | 67             //int[] index = GetIndex(source, dest); | 
|  | 68             //IValueMapper[] mappers = GetValueMappers(source, dest, index); | 
|  | 69 | 
|  | 70             //foreach (var valueMapper in mappers) | 
|  | 71             //{ | 
|  | 72 | 
|  | 73             //} | 
|  | 74 | 
|  | 75             InitSchema(dataReader); | 
|  | 76 | 
|  | 77             if (mapper.ColParent) | 
|  | 78             { | 
|  | 79                 FillObject(mapper, dataReader, destObject); | 
|  | 80                 while (dataReader.Read()) | 
|  | 81                 { | 
|  | 82                     destObject = FillObject(destObject, mapper, dataReader); | 
|  | 83                 } | 
|  | 84             } | 
|  | 85             else | 
|  | 86                  FillObject(mapper, dataReader, destObject); | 
|  | 87         } | 
|  | 88 | 
|  | 89         public override IList MapDataReaderToList( | 
|  | 90             IDataReader reader, | 
|  | 91             IList list, | 
|  | 92             Type destObjectType, | 
|  | 93             params object[] parameters) | 
|  | 94         { | 
|  | 95             return internalMapDataReaderToList(reader, list, destObjectType, parameters); | 
|  | 96         } | 
|  | 97 | 
|  | 98         #endregion | 
|  | 99 | 
|  | 100         #region Private methods | 
|  | 101 | 
|  | 102         private object FillObject(object result, IObjectMapper mapper, IDataReader datareader) | 
|  | 103         { | 
|  | 104             foreach (IMapper map in mapper.PropertiesMapping) | 
|  | 105             { | 
|  | 106                 if (map is IObjectMapper && (map as IObjectMapper).IsLazy) | 
|  | 107                     continue; | 
|  | 108 | 
|  | 109                 if (map is CollectionFullObjectMapper) | 
|  | 110                 { | 
|  | 111                     var collectionFullObjectMapper = (CollectionFullObjectMapper) map; | 
|  | 112                     object listInstance = collectionFullObjectMapper.Getter(result); | 
|  | 113                     if (listInstance == null) | 
|  | 114                     { | 
|  | 115                         listInstance = Activator.CreateInstance((map as CollectionFullObjectMapper).PropertyCollectionType); | 
|  | 116                         map.Setter(result, listInstance); | 
|  | 117                     } | 
|  | 118                     var list = (IList) listInstance; | 
|  | 119                     object fillObject = ((CollectionFullObjectMapper)map).CreateInstance(); | 
|  | 120                     FillObject((CollectionFullObjectMapper) map, datareader, fillObject); | 
|  | 121 | 
|  | 122                     if (list.Count > 0) | 
|  | 123                     { | 
|  | 124                         var curMapper = (FullObjectMapper)GetObjectMapper(fillObject.GetType()); | 
|  | 125 | 
|  | 126                         object lastElement = list[list.Count - 1]; | 
|  | 127 | 
|  | 128                         bool allPksEqual = true; | 
|  | 129 | 
|  | 130                         //This is needed, because DBValue can be Null, but the Field can be Guid, wich then is filled with Guid.Empty and this is also a valid value! | 
|  | 131                         /*foreach (var pkIndex in pkIndexes) | 
|  | 132                         { | 
|  | 133                             var dbValue = reader.GetValue(pkIndex); | 
|  | 134                             if (dbValue == DBNull.Value) | 
|  | 135                             { | 
|  | 136                                 pkIsNull = true; | 
|  | 137                                 break; | 
|  | 138                             } | 
|  | 139                         }*/ | 
|  | 140 | 
|  | 141                         foreach (var pkGetter in curMapper.PrimaryKeyValueGetters) | 
|  | 142                         { | 
|  | 143                             object lastPk = pkGetter.Invoke(lastElement); | 
|  | 144                             object currentPk = pkGetter.Invoke(fillObject); | 
|  | 145 | 
|  | 146                             if (!lastPk.Equals(currentPk)) | 
|  | 147                             { | 
|  | 148                                 allPksEqual = false; | 
|  | 149                                 break; | 
|  | 150                             } | 
|  | 151                         } | 
|  | 152 | 
|  | 153                         if (allPksEqual) | 
|  | 154                             continue; | 
|  | 155                     } | 
|  | 156 | 
|  | 157                     ((IList) listInstance).Add(fillObject); | 
|  | 158                 } | 
|  | 159             } | 
|  | 160 | 
|  | 161             return result; | 
|  | 162         } | 
|  | 163 | 
|  | 164         private void FillObject(IObjectMapper mapper, IDataReader datareader, object result) | 
|  | 165         { | 
|  | 166             foreach (IMapper map in mapper.PropertiesMapping) | 
|  | 167             { | 
|  | 168                 if (map is IObjectMapper && (map as IObjectMapper).IsLazy) | 
|  | 169                     continue; | 
|  | 170 | 
|  | 171                 if  (map is ValueMapper) | 
|  | 172                 { | 
|  | 173                     if (((ValueMapper)map).SetDataReaderIndex(_schemaColumns)) | 
|  | 174                         continue; | 
|  | 175                 } | 
|  | 176 | 
|  | 177                 if (datareader.IsDBNull(map.DataReaderIndex)) | 
|  | 178                     continue; | 
|  | 179 | 
|  | 180                 if (map is ValueMapper) | 
|  | 181                 { | 
|  | 182                     object value = datareader.GetValue(map.DataReaderIndex); | 
|  | 183 | 
|  | 184                     try | 
|  | 185                     { | 
|  | 186                         map.Setter(result, value); | 
|  | 187                     } | 
|  | 188                     catch (Exception exception) | 
|  | 189                     { | 
|  | 190                         throw new Exception( | 
|  | 191                             string.Format("FillOject failed for field : {0} of class: {1}.\nColumn name : {2} Db type is: {3} and value : {4}", | 
|  | 192                                           map.PropertyName, mapper.PropertyType, | 
|  | 193                                           ((ValueMapper) map).ColumnName, | 
|  | 194                                           value == null ? "Null" : value.GetType().ToString(), value), exception); | 
|  | 195                     } | 
|  | 196                 } | 
|  | 197 | 
|  | 198                 if (map is FullObjectMapper) | 
|  | 199                 { | 
|  | 200                     object fillObject = ((FullObjectMapper) map).CreateInstance(); | 
|  | 201                     FillObject((FullObjectMapper) map, datareader, fillObject); | 
|  | 202                     map.Setter(result, fillObject); | 
|  | 203                 } | 
|  | 204 | 
|  | 205                 if (map is CollectionFullObjectMapper) | 
|  | 206                 { | 
|  | 207                     var collectionFullObjectMapper = (CollectionFullObjectMapper) map; | 
|  | 208 | 
|  | 209                     object listInstance = collectionFullObjectMapper.Getter(result); | 
|  | 210                     if (listInstance == null) | 
|  | 211                     { | 
|  | 212                         listInstance = Activator.CreateInstance((map as CollectionFullObjectMapper).PropertyCollectionType); | 
|  | 213                         map.Setter(result, listInstance); | 
|  | 214                     } | 
|  | 215 | 
|  | 216                     object fillObject = ((CollectionFullObjectMapper)map).CreateInstance(); | 
|  | 217                     FillObject((CollectionFullObjectMapper) map, datareader, fillObject); | 
|  | 218                     ((IList) listInstance).Add(fillObject); | 
|  | 219                 } | 
|  | 220             } | 
|  | 221         } | 
|  | 222 | 
|  | 223         private void InitSchema(IDataReader reader) | 
|  | 224         { | 
|  | 225             _schemaColumns = new List<string>(); | 
|  | 226             _schema = reader.GetSchemaTable(); | 
|  | 227             if (_schema != null) | 
|  | 228                 _schema.Rows.Cast<DataRow>().ToList().ForEach(dr => _schemaColumns.Add((string)dr["ColumnName"])); | 
|  | 229         } | 
|  | 230 | 
|  | 231         private IList internalMapDataReaderToList( | 
|  | 232             IDataReader reader, | 
|  | 233             IList list, | 
|  | 234             Type destObjectType, | 
|  | 235             params object[] parameters) | 
|  | 236         { | 
|  | 237             FullObjectMapper mapper = (FullObjectMapper)GetObjectMapper(destObjectType); | 
|  | 238 | 
|  | 239             InitSchema(reader); | 
|  | 240 | 
|  | 241             object currentItem = null; | 
|  | 242 | 
|  | 243             List<int> pkIndexes = new List<int>(); | 
|  | 244             foreach (var nm in mapper.PrimaryKeyNames) | 
|  | 245             { | 
|  | 246                 pkIndexes.Add(mapper.PropertiesMapping.First(x => x.PropertyName == nm).DataReaderIndex); | 
|  | 247             } | 
|  | 248 | 
|  | 249             while (reader.Read()) | 
|  | 250             { | 
|  | 251                 var result = mapper.CreateInstance(); | 
|  | 252 | 
|  | 253                 FillObject(mapper, reader, result); | 
|  | 254                 if (currentItem == null) | 
|  | 255                 { | 
|  | 256                     currentItem = result; | 
|  | 257                     list.Add(result); | 
|  | 258                     continue; | 
|  | 259                 } | 
|  | 260 | 
|  | 261                 bool pkIsNull = false; | 
|  | 262                 bool allPksEqual = true; | 
|  | 263 | 
|  | 264                 //This is needed, because DBValue can be Null, but the Field can be Guid, wich then is filled with Guid.Empty and this is also a valid value! | 
|  | 265                 foreach (var pkIndex in pkIndexes) | 
|  | 266                 { | 
|  | 267                     var dbValue = reader.GetValue(pkIndex); | 
|  | 268                     if (dbValue == DBNull.Value) | 
|  | 269                     { | 
|  | 270                         pkIsNull = true; | 
|  | 271                         break; | 
|  | 272                     } | 
|  | 273                 } | 
|  | 274 | 
|  | 275                 if (!pkIsNull) | 
|  | 276                     foreach (var pkGetter in mapper.PrimaryKeyValueGetters) | 
|  | 277                     { | 
|  | 278                         object resultPk = pkGetter.Invoke(result); | 
|  | 279                         object currentItemPk = pkGetter.Invoke(currentItem); | 
|  | 280 | 
|  | 281                         if (!resultPk.Equals(currentItemPk)) | 
|  | 282                         { | 
|  | 283                             allPksEqual = false; | 
|  | 284                             break; | 
|  | 285                         } | 
|  | 286                     } | 
|  | 287 | 
|  | 288                 if (!pkIsNull && !allPksEqual) | 
|  | 289                 { | 
|  | 290                     currentItem = result; | 
|  | 291                     list.Add(result); | 
|  | 292                     //continue; | 
|  | 293                 } | 
|  | 294 | 
|  | 295                 if (mapper.ColParent) | 
|  | 296                 { | 
|  | 297                     FillObject(currentItem, mapper, reader); | 
|  | 298                 } | 
|  | 299             } | 
|  | 300 | 
|  | 301             return list; | 
|  | 302         } | 
|  | 303 | 
|  | 304         #endregion | 
|  | 305     } | 
|  | 306 } |