Mercurial > pub > bltoolkit
comparison Extensions/JointureAddOn/Mapping/FullObjectMapper.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f990fcb411a9 |
---|---|
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 } |