| 
0
 | 
     1 #region
 | 
| 
 | 
     2 
 | 
| 
 | 
     3 using System;
 | 
| 
 | 
     4 using System.Collections;
 | 
| 
 | 
     5 using System.Collections.Generic;
 | 
| 
 | 
     6 using System.Linq;
 | 
| 
 | 
     7 using System.Reflection;
 | 
| 
 | 
     8 using BLToolkit.Data;
 | 
| 
 | 
     9 using BLToolkit.DataAccess;
 | 
| 
 | 
    10 using BLToolkit.Emit;
 | 
| 
 | 
    11 using BLToolkit.Reflection;
 | 
| 
 | 
    12 using BLToolkit.Reflection.Extension;
 | 
| 
 | 
    13 
 | 
| 
 | 
    14 #endregion
 | 
| 
 | 
    15 
 | 
| 
 | 
    16 namespace BLToolkit.Mapping
 | 
| 
 | 
    17 {
 | 
| 
 | 
    18     public class FullObjectMapper : ObjectMapper, IObjectMapper
 | 
| 
 | 
    19     {
 | 
| 
 | 
    20         #region Fields
 | 
| 
 | 
    21 
 | 
| 
 | 
    22         private static readonly object SetterHandlersLock = new object();
 | 
| 
 | 
    23 
 | 
| 
 | 
    24         private static readonly Dictionary<Type, Dictionary<string, SetHandler>> SettersHandlers =
 | 
| 
 | 
    25             new Dictionary<Type, Dictionary<string, SetHandler>>();
 | 
| 
 | 
    26 
 | 
| 
 | 
    27         private static readonly Dictionary<Type, Dictionary<string, GetHandler>> GettersHandlers =
 | 
| 
 | 
    28             new Dictionary<Type, Dictionary<string, GetHandler>>();
 | 
| 
 | 
    29 
 | 
| 
 | 
    30         private readonly DbManager _db;
 | 
| 
 | 
    31         private readonly FactoryType _factoryType;
 | 
| 
 | 
    32         private readonly bool _ignoreLazyLoad;
 | 
| 
 | 
    33 
 | 
| 
 | 
    34         #endregion
 | 
| 
 | 
    35 
 | 
| 
 | 
    36         public FullObjectMapper(DbManager db, bool ignoreLazyLoading, FactoryType factoryType)
 | 
| 
 | 
    37         {
 | 
| 
 | 
    38             _db = db;
 | 
| 
 | 
    39             _ignoreLazyLoad = ignoreLazyLoading;
 | 
| 
 | 
    40             _factoryType = factoryType;
 | 
| 
 | 
    41 
 | 
| 
 | 
    42             PropertiesMapping = new List<IMapper>();
 | 
| 
 | 
    43             PrimaryKeyValueGetters = new List<GetHandler>();
 | 
| 
 | 
    44             PrimaryKeyNames = new List<string>();
 | 
| 
 | 
    45         }
 | 
| 
 | 
    46 
 | 
| 
 | 
    47         #region IPropertiesMapping Members
 | 
| 
 | 
    48 
 | 
| 
 | 
    49         public List<IMapper> PropertiesMapping { get; private set; }
 | 
| 
 | 
    50         public IPropertiesMapping ParentMapping { get; set; }
 | 
| 
 | 
    51 
 | 
| 
 | 
    52         #endregion
 | 
| 
 | 
    53 
 | 
| 
 | 
    54         public bool IsNullable { get; set; }
 | 
| 
 | 
    55         public bool ColParent { get; set; }
 | 
| 
 | 
    56 
 | 
| 
 | 
    57         #region IMapper Members
 | 
| 
 | 
    58 
 | 
| 
 | 
    59         public int DataReaderIndex { get; set; }
 | 
| 
 | 
    60         public SetHandler Setter { get; set; }
 | 
| 
 | 
    61         public Type PropertyType { get; set; }
 | 
| 
 | 
    62         public string PropertyName { get; set; }
 | 
| 
 | 
    63         public Association Association { get; set; }
 | 
| 
 | 
    64 
 | 
| 
 | 
    65         #endregion
 | 
| 
 | 
    66 
 | 
| 
 | 
    67         #region IObjectMapper
 | 
| 
 | 
    68 
 | 
| 
 | 
    69         public bool IsLazy { get; set; }
 | 
| 
 | 
    70         public bool ContainsLazyChild { get; set; }
 | 
| 
 | 
    71         public GetHandler Getter { get; set; }
 | 
| 
 | 
    72 
 | 
| 
 | 
    73         public List<string> PrimaryKeyNames { get; set; }
 | 
| 
 | 
    74 
 | 
| 
 | 
    75         #endregion
 | 
| 
 | 
    76 
 | 
| 
 | 
    77         #region ILazyMapper
 | 
| 
 | 
    78 
 | 
| 
 | 
    79         public GetHandler ParentKeyGetter { get; set; }
 | 
| 
 | 
    80         public List<GetHandler> PrimaryKeyValueGetters { get; set; }
 | 
| 
 | 
    81 
 | 
| 
 | 
    82         #endregion
 | 
| 
 | 
    83 
 | 
| 
 | 
    84         #region Overrides
 | 
| 
 | 
    85 
 | 
| 
 | 
    86         public override void Init(MappingSchema mappingSchema, Type type)
 | 
| 
 | 
    87         {
 | 
| 
 | 
    88             PropertyType = type;
 | 
| 
 | 
    89 
 | 
| 
 | 
    90             // TODO implement this method
 | 
| 
 | 
    91             base.Init(mappingSchema, type);
 | 
| 
 | 
    92 
 | 
| 
 | 
    93             int startIndex = 0;
 | 
| 
 | 
    94             GetObjectMapper(this, ref startIndex, _typeAccessor);
 | 
| 
 | 
    95         }
 | 
| 
 | 
    96 
 | 
| 
 | 
    97         public override object CreateInstance()
 | 
| 
 | 
    98         {
 | 
| 
 | 
    99             object result = ContainsLazyChild
 | 
| 
 | 
   100                                 ? (_factoryType == FactoryType.LazyLoading
 | 
| 
 | 
   101                                        ? TypeFactory.LazyLoading.Create(PropertyType, this, LoadLazy)
 | 
| 
 | 
   102                                        : TypeFactory.LazyLoadingWithDataBinding.Create(PropertyType, this, LoadLazy))
 | 
| 
 | 
   103                                 : FunctionFactory.Remote.CreateInstance(PropertyType);
 | 
| 
 | 
   104 
 | 
| 
 | 
   105             return result;
 | 
| 
 | 
   106         }
 | 
| 
 | 
   107 
 | 
| 
 | 
   108         public override object CreateInstance(InitContext context)
 | 
| 
 | 
   109         {
 | 
| 
 | 
   110             return CreateInstance();
 | 
| 
 | 
   111         }
 | 
| 
 | 
   112 
 | 
| 
 | 
   113         #endregion
 | 
| 
 | 
   114 
 | 
| 
 | 
   115         #region Private methods
 | 
| 
 | 
   116 
 | 
| 
 | 
   117         private TableDescription GetTableDescription(Type type)
 | 
| 
 | 
   118         {
 | 
| 
 | 
   119             var tableDescription = new TableDescription();
 | 
| 
 | 
   120             object[] tableAtt = type.GetCustomAttributes(typeof (TableNameAttribute), true);
 | 
| 
 | 
   121 
 | 
| 
 | 
   122             if (tableAtt.Length > 0)
 | 
| 
 | 
   123             {
 | 
| 
 | 
   124                 var tna = (TableNameAttribute) tableAtt[0];
 | 
| 
 | 
   125 
 | 
| 
 | 
   126                 tableDescription.Database = tna.Database;
 | 
| 
 | 
   127                 tableDescription.Owner = tna.Owner;
 | 
| 
 | 
   128                 tableDescription.TableName = tna.Name;
 | 
| 
 | 
   129             }
 | 
| 
 | 
   130 
 | 
| 
 | 
   131             return tableDescription;
 | 
| 
 | 
   132         }
 | 
| 
 | 
   133 
 | 
| 
 | 
   134         private IMapper GetObjectMapper(IObjectMapper mapper, ref int startIndex, TypeAccessor akTypeAccessor)
 | 
| 
 | 
   135         {
 | 
| 
 | 
   136             //Todo: Remove this Call!
 | 
| 
 | 
   137             _extension = TypeExtension.GetTypeExtension(mapper.PropertyType /*_typeAccessor.OriginalType*/, MappingSchema.Extensions);
 | 
| 
 | 
   138 
 | 
| 
 | 
   139             Type mapperType = mapper.PropertyType;
 | 
| 
 | 
   140             var objectMappers = new List<IObjectMapper>();
 | 
| 
 | 
   141 
 | 
| 
 | 
   142             TableDescription tableDescription = GetTableDescription(mapperType);
 | 
| 
 | 
   143 
 | 
| 
 | 
   144             lock (SetterHandlersLock)
 | 
| 
 | 
   145             {
 | 
| 
 | 
   146                 if (!SettersHandlers.ContainsKey(mapperType))
 | 
| 
 | 
   147                     SettersHandlers.Add(mapperType, new Dictionary<string, SetHandler>());
 | 
| 
 | 
   148 
 | 
| 
 | 
   149                 if (!GettersHandlers.ContainsKey(mapperType))
 | 
| 
 | 
   150                     GettersHandlers.Add(mapperType, new Dictionary<string, GetHandler>());
 | 
| 
 | 
   151             }
 | 
| 
 | 
   152 
 | 
| 
 | 
   153             PropertyInfo[] properties = mapperType.GetProperties();
 | 
| 
 | 
   154 
 | 
| 
 | 
   155             MemberAccessor primaryKeyMemberAccessor = null;
 | 
| 
 | 
   156             foreach (MemberAccessor ma in akTypeAccessor)
 | 
| 
 | 
   157             {
 | 
| 
 | 
   158                 //  Setters
 | 
| 
 | 
   159                 lock (SetterHandlersLock)
 | 
| 
 | 
   160                 {
 | 
| 
 | 
   161                     if (!SettersHandlers[mapper.PropertyType].ContainsKey(ma.Name))
 | 
| 
 | 
   162                     {
 | 
| 
 | 
   163                         SettersHandlers[mapper.PropertyType].Add(ma.Name, ma.SetValue);
 | 
| 
 | 
   164                     }
 | 
| 
 | 
   165                 }
 | 
| 
 | 
   166 
 | 
| 
 | 
   167                 if (GetPrimaryKey(ma) != null)
 | 
| 
 | 
   168                 {
 | 
| 
 | 
   169                     primaryKeyMemberAccessor = ma;
 | 
| 
 | 
   170 
 | 
| 
 | 
   171                     lock (SetterHandlersLock)
 | 
| 
 | 
   172                     {
 | 
| 
 | 
   173                         if (!GettersHandlers[mapperType].ContainsKey(ma.Name))
 | 
| 
 | 
   174                         {
 | 
| 
 | 
   175                             GettersHandlers[mapperType].Add(ma.Name, ma.GetValue);
 | 
| 
 | 
   176                         }
 | 
| 
 | 
   177                     }
 | 
| 
 | 
   178                     mapper.PrimaryKeyValueGetters.Add(GettersHandlers[mapperType][ma.Name]);
 | 
| 
 | 
   179                     mapper.PrimaryKeyNames.Add(ma.Name);
 | 
| 
 | 
   180 
 | 
| 
 | 
   181                     if (mapper.Association != null && (mapper.Association.OtherKey == null || mapper.Association.OtherKey.Length == 0))
 | 
| 
 | 
   182                     {
 | 
| 
 | 
   183                         mapper.Association.OtherKey = new[] {ma.Name};
 | 
| 
 | 
   184                     }
 | 
| 
 | 
   185                 }
 | 
| 
 | 
   186             }
 | 
| 
 | 
   187             if (primaryKeyMemberAccessor == null)
 | 
| 
 | 
   188                 throw new Exception("PrimaryKey attribute not found on type: " + mapperType);
 | 
| 
 | 
   189 
 | 
| 
 | 
   190             foreach (PropertyInfo prop in properties)
 | 
| 
 | 
   191             {
 | 
| 
 | 
   192                 var ma = akTypeAccessor.First(x => x.Name == prop.Name);
 | 
| 
 | 
   193 
 | 
| 
 | 
   194                 // Check if the accessor is an association
 | 
| 
 | 
   195                 var association = GetAssociation(ma);
 | 
| 
 | 
   196                 if (association != null)
 | 
| 
 | 
   197                 {
 | 
| 
 | 
   198                     //  Getters for IObjectMapper
 | 
| 
 | 
   199                     lock (SetterHandlersLock)
 | 
| 
 | 
   200                         if (!GettersHandlers[mapperType].ContainsKey(prop.Name))
 | 
| 
 | 
   201                         {
 | 
| 
 | 
   202                             GettersHandlers[mapperType].Add(prop.Name, ma.GetValue);
 | 
| 
 | 
   203                         }
 | 
| 
 | 
   204 
 | 
| 
 | 
   205                     bool isCollection = prop.PropertyType.GetInterfaces().ToList().Contains(typeof (IList));
 | 
| 
 | 
   206                     IObjectMapper propertiesMapping;
 | 
| 
 | 
   207                     if (!isCollection)
 | 
| 
 | 
   208                     {
 | 
| 
 | 
   209                         // TODO Generate this instance using the CreateObjectMapperInstance method of fullMappingSchema
 | 
| 
 | 
   210                         // _db.MappingSchema.CreateObjectMapperInstance(prop.PropertyType)
 | 
| 
 | 
   211 
 | 
| 
 | 
   212                         propertiesMapping = new FullObjectMapper(_db, _ignoreLazyLoad, _factoryType)
 | 
| 
 | 
   213                             {
 | 
| 
 | 
   214                                 PropertyType = prop.PropertyType,
 | 
| 
 | 
   215                                 IsNullable = association.CanBeNull,
 | 
| 
 | 
   216                                 Getter = GettersHandlers[mapperType][prop.Name],
 | 
| 
 | 
   217                             };
 | 
| 
 | 
   218                     }
 | 
| 
 | 
   219                     else
 | 
| 
 | 
   220                     {
 | 
| 
 | 
   221                         Type listElementType = GetGenericType(prop.PropertyType);
 | 
| 
 | 
   222                         TableDescription colElementTableDescription = GetTableDescription(listElementType);
 | 
| 
 | 
   223 
 | 
| 
 | 
   224                         // TODO Generate this instance using the CreateObjectMapperInstance method of fullMappingSchema
 | 
| 
 | 
   225                         propertiesMapping = new CollectionFullObjectMapper(_db, _factoryType)
 | 
| 
 | 
   226                             {
 | 
| 
 | 
   227                                 PropertyType = listElementType,
 | 
| 
 | 
   228                                 Getter = GettersHandlers[mapperType][prop.Name],
 | 
| 
 | 
   229                                 TableName = colElementTableDescription.TableName,
 | 
| 
 | 
   230                                 PropertyCollectionType = prop.PropertyType,
 | 
| 
 | 
   231                             };
 | 
| 
 | 
   232 
 | 
| 
 | 
   233                         if (mapper is FullObjectMapper)
 | 
| 
 | 
   234                             ((FullObjectMapper) mapper).ColParent = true;
 | 
| 
 | 
   235                     }
 | 
| 
 | 
   236 
 | 
| 
 | 
   237                     if (association.ThisKey == null || association.ThisKey.Length == 0)
 | 
| 
 | 
   238                         association.ThisKey = new[] {primaryKeyMemberAccessor.Name};
 | 
| 
 | 
   239 
 | 
| 
 | 
   240                     bool isLazy = false;
 | 
| 
 | 
   241                     if (!_ignoreLazyLoad)
 | 
| 
 | 
   242                     {
 | 
| 
 | 
   243                         var lazy = GetLazyInstance(ma); // prop.GetCustomAttributes(typeof(LazyInstanceAttribute), true);
 | 
| 
 | 
   244                         if (lazy)
 | 
| 
 | 
   245                         {
 | 
| 
 | 
   246                             isLazy = true;
 | 
| 
 | 
   247                             mapper.ContainsLazyChild = true;
 | 
| 
 | 
   248 
 | 
| 
 | 
   249                             //  Getters
 | 
| 
 | 
   250                             lock (SetterHandlersLock)
 | 
| 
 | 
   251                                 if (!GettersHandlers[mapperType].ContainsKey(primaryKeyMemberAccessor.Name))
 | 
| 
 | 
   252                                 {
 | 
| 
 | 
   253                                     GettersHandlers[mapperType].Add(primaryKeyMemberAccessor.Name, primaryKeyMemberAccessor.GetValue);
 | 
| 
 | 
   254                                 }
 | 
| 
 | 
   255                         }
 | 
| 
 | 
   256                     }
 | 
| 
 | 
   257 
 | 
| 
 | 
   258                     propertiesMapping.Association = association;
 | 
| 
 | 
   259                     propertiesMapping.PropertyName = prop.Name;
 | 
| 
 | 
   260                     propertiesMapping.IsLazy = isLazy;
 | 
| 
 | 
   261                     propertiesMapping.Setter = SettersHandlers[mapperType][prop.Name];
 | 
| 
 | 
   262 
 | 
| 
 | 
   263                     if (propertiesMapping.IsLazy)
 | 
| 
 | 
   264                     {
 | 
| 
 | 
   265                         propertiesMapping.ParentKeyGetter = GettersHandlers[mapperType][primaryKeyMemberAccessor.Name];
 | 
| 
 | 
   266                     }
 | 
| 
 | 
   267                     objectMappers.Add(propertiesMapping);
 | 
| 
 | 
   268                 }
 | 
| 
 | 
   269                 else
 | 
| 
 | 
   270                 {
 | 
| 
 | 
   271                     var mapIgnore = GetMapIgnore(ma);
 | 
| 
 | 
   272                     if (mapIgnore)
 | 
| 
 | 
   273                         continue;
 | 
| 
 | 
   274 
 | 
| 
 | 
   275                     var mapField = GetMapField(ma);
 | 
| 
 | 
   276                     string columnName = mapField != null ? mapField.MapName : prop.Name;
 | 
| 
 | 
   277 
 | 
| 
 | 
   278                     var map = new ValueMapper
 | 
| 
 | 
   279                         {
 | 
| 
 | 
   280                             PropertyName = prop.Name,
 | 
| 
 | 
   281                             PropertyType = prop.PropertyType,
 | 
| 
 | 
   282                             DataReaderIndex = startIndex,
 | 
| 
 | 
   283                             Setter = SettersHandlers[mapperType][prop.Name],
 | 
| 
 | 
   284                             TableName = tableDescription.TableName,
 | 
| 
 | 
   285                             ColumnName = columnName,
 | 
| 
 | 
   286                         };
 | 
| 
 | 
   287 
 | 
| 
 | 
   288                     var mapColumnName = map.GetColumnName(columnName);
 | 
| 
 | 
   289                     map.ColumnAlias = columnName == mapColumnName ? null : mapColumnName;
 | 
| 
 | 
   290 
 | 
| 
 | 
   291                     mapper.PropertiesMapping.Add(map);
 | 
| 
 | 
   292 
 | 
| 
 | 
   293                     var pkField = GetPrimaryKey(ma);
 | 
| 
 | 
   294                     if (pkField != null)
 | 
| 
 | 
   295                         mapper.DataReaderIndex = startIndex;
 | 
| 
 | 
   296 
 | 
| 
 | 
   297                     startIndex++;
 | 
| 
 | 
   298                 }
 | 
| 
 | 
   299             }
 | 
| 
 | 
   300 
 | 
| 
 | 
   301             foreach (IObjectMapper objMap in objectMappers)
 | 
| 
 | 
   302             {
 | 
| 
 | 
   303                 #region Check mapping recursion
 | 
| 
 | 
   304 
 | 
| 
 | 
   305                 IObjectMapper cel = mapper;
 | 
| 
 | 
   306                 while (cel != null)
 | 
| 
 | 
   307                 {
 | 
| 
 | 
   308                     if (mapper.PropertyType == objMap.PropertyType)
 | 
| 
 | 
   309                         continue;
 | 
| 
 | 
   310 
 | 
| 
 | 
   311                     cel = (IObjectMapper) cel.ParentMapping;
 | 
| 
 | 
   312                 }
 | 
| 
 | 
   313 
 | 
| 
 | 
   314                 #endregion
 | 
| 
 | 
   315 
 | 
| 
 | 
   316                 objMap.ParentMapping = mapper;
 | 
| 
 | 
   317                 mapper.PropertiesMapping.Add(GetObjectMapper(objMap, ref startIndex, MappingSchema.GetObjectMapper(objMap.PropertyType).TypeAccessor));
 | 
| 
 | 
   318             }
 | 
| 
 | 
   319 
 | 
| 
 | 
   320             return mapper;
 | 
| 
 | 
   321         }
 | 
| 
 | 
   322 
 | 
| 
 | 
   323         protected object LoadLazy(IMapper mapper, object proxy, Type parentType)
 | 
| 
 | 
   324         {
 | 
| 
 | 
   325             var lazyMapper = (ILazyMapper) mapper;
 | 
| 
 | 
   326             object key = lazyMapper.ParentKeyGetter(proxy);
 | 
| 
 | 
   327 
 | 
| 
 | 
   328             var fullSqlQuery = new FullSqlQuery(_db, ignoreLazyLoad: true);
 | 
| 
 | 
   329             object parentLoadFull = fullSqlQuery.SelectByKey(parentType, key);
 | 
| 
 | 
   330             if (parentLoadFull == null)
 | 
| 
 | 
   331             {
 | 
| 
 | 
   332                 object value = Activator.CreateInstance(mapper is CollectionFullObjectMapper
 | 
| 
 | 
   333                                                             ? (mapper as CollectionFullObjectMapper).PropertyCollectionType
 | 
| 
 | 
   334                                                             : mapper.PropertyType);
 | 
| 
 | 
   335                 return value;
 | 
| 
 | 
   336             }
 | 
| 
 | 
   337 
 | 
| 
 | 
   338             var objectMapper = (IObjectMapper) mapper;
 | 
| 
 | 
   339             return objectMapper.Getter(parentLoadFull);
 | 
| 
 | 
   340         }
 | 
| 
 | 
   341 
 | 
| 
 | 
   342         private static Type GetGenericType(Type t)
 | 
| 
 | 
   343         {
 | 
| 
 | 
   344             if (t.IsGenericType)
 | 
| 
 | 
   345             {
 | 
| 
 | 
   346                 Type[] at = t.GetGenericArguments();
 | 
| 
 | 
   347                 return at.FirstOrDefault();
 | 
| 
 | 
   348             }
 | 
| 
 | 
   349             return null;
 | 
| 
 | 
   350         }
 | 
| 
 | 
   351 
 | 
| 
 | 
   352         #endregion
 | 
| 
 | 
   353     }
 | 
| 
 | 
   354 } |