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 } |