Mercurial > pub > bltoolkit
view Extensions/JointureAddOn/Mapping/FullObjectMapper.cs @ 9:1e85f66cf767 default tip
update bltoolkit
author | nickolay |
---|---|
date | Thu, 05 Apr 2018 20:53:26 +0300 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
#region using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using BLToolkit.Data; using BLToolkit.DataAccess; using BLToolkit.Emit; using BLToolkit.Reflection; using BLToolkit.Reflection.Extension; #endregion namespace BLToolkit.Mapping { public class FullObjectMapper : ObjectMapper, IObjectMapper { #region Fields private static readonly object SetterHandlersLock = new object(); private static readonly Dictionary<Type, Dictionary<string, SetHandler>> SettersHandlers = new Dictionary<Type, Dictionary<string, SetHandler>>(); private static readonly Dictionary<Type, Dictionary<string, GetHandler>> GettersHandlers = new Dictionary<Type, Dictionary<string, GetHandler>>(); private readonly DbManager _db; private readonly FactoryType _factoryType; private readonly bool _ignoreLazyLoad; #endregion public FullObjectMapper(DbManager db, bool ignoreLazyLoading, FactoryType factoryType) { _db = db; _ignoreLazyLoad = ignoreLazyLoading; _factoryType = factoryType; PropertiesMapping = new List<IMapper>(); PrimaryKeyValueGetters = new List<GetHandler>(); PrimaryKeyNames = new List<string>(); } #region IPropertiesMapping Members public List<IMapper> PropertiesMapping { get; private set; } public IPropertiesMapping ParentMapping { get; set; } #endregion public bool IsNullable { get; set; } public bool ColParent { get; set; } #region IMapper Members public int DataReaderIndex { get; set; } public SetHandler Setter { get; set; } public Type PropertyType { get; set; } public string PropertyName { get; set; } public Association Association { get; set; } #endregion #region IObjectMapper public bool IsLazy { get; set; } public bool ContainsLazyChild { get; set; } public GetHandler Getter { get; set; } public List<string> PrimaryKeyNames { get; set; } #endregion #region ILazyMapper public GetHandler ParentKeyGetter { get; set; } public List<GetHandler> PrimaryKeyValueGetters { get; set; } #endregion #region Overrides public override void Init(MappingSchema mappingSchema, Type type) { PropertyType = type; // TODO implement this method base.Init(mappingSchema, type); int startIndex = 0; GetObjectMapper(this, ref startIndex, _typeAccessor); } public override object CreateInstance() { object result = ContainsLazyChild ? (_factoryType == FactoryType.LazyLoading ? TypeFactory.LazyLoading.Create(PropertyType, this, LoadLazy) : TypeFactory.LazyLoadingWithDataBinding.Create(PropertyType, this, LoadLazy)) : FunctionFactory.Remote.CreateInstance(PropertyType); return result; } public override object CreateInstance(InitContext context) { return CreateInstance(); } #endregion #region Private methods private TableDescription GetTableDescription(Type type) { var tableDescription = new TableDescription(); object[] tableAtt = type.GetCustomAttributes(typeof (TableNameAttribute), true); if (tableAtt.Length > 0) { var tna = (TableNameAttribute) tableAtt[0]; tableDescription.Database = tna.Database; tableDescription.Owner = tna.Owner; tableDescription.TableName = tna.Name; } return tableDescription; } private IMapper GetObjectMapper(IObjectMapper mapper, ref int startIndex, TypeAccessor akTypeAccessor) { //Todo: Remove this Call! _extension = TypeExtension.GetTypeExtension(mapper.PropertyType /*_typeAccessor.OriginalType*/, MappingSchema.Extensions); Type mapperType = mapper.PropertyType; var objectMappers = new List<IObjectMapper>(); TableDescription tableDescription = GetTableDescription(mapperType); lock (SetterHandlersLock) { if (!SettersHandlers.ContainsKey(mapperType)) SettersHandlers.Add(mapperType, new Dictionary<string, SetHandler>()); if (!GettersHandlers.ContainsKey(mapperType)) GettersHandlers.Add(mapperType, new Dictionary<string, GetHandler>()); } PropertyInfo[] properties = mapperType.GetProperties(); MemberAccessor primaryKeyMemberAccessor = null; foreach (MemberAccessor ma in akTypeAccessor) { // Setters lock (SetterHandlersLock) { if (!SettersHandlers[mapper.PropertyType].ContainsKey(ma.Name)) { SettersHandlers[mapper.PropertyType].Add(ma.Name, ma.SetValue); } } if (GetPrimaryKey(ma) != null) { primaryKeyMemberAccessor = ma; lock (SetterHandlersLock) { if (!GettersHandlers[mapperType].ContainsKey(ma.Name)) { GettersHandlers[mapperType].Add(ma.Name, ma.GetValue); } } mapper.PrimaryKeyValueGetters.Add(GettersHandlers[mapperType][ma.Name]); mapper.PrimaryKeyNames.Add(ma.Name); if (mapper.Association != null && (mapper.Association.OtherKey == null || mapper.Association.OtherKey.Length == 0)) { mapper.Association.OtherKey = new[] {ma.Name}; } } } if (primaryKeyMemberAccessor == null) throw new Exception("PrimaryKey attribute not found on type: " + mapperType); foreach (PropertyInfo prop in properties) { var ma = akTypeAccessor.First(x => x.Name == prop.Name); // Check if the accessor is an association var association = GetAssociation(ma); if (association != null) { // Getters for IObjectMapper lock (SetterHandlersLock) if (!GettersHandlers[mapperType].ContainsKey(prop.Name)) { GettersHandlers[mapperType].Add(prop.Name, ma.GetValue); } bool isCollection = prop.PropertyType.GetInterfaces().ToList().Contains(typeof (IList)); IObjectMapper propertiesMapping; if (!isCollection) { // TODO Generate this instance using the CreateObjectMapperInstance method of fullMappingSchema // _db.MappingSchema.CreateObjectMapperInstance(prop.PropertyType) propertiesMapping = new FullObjectMapper(_db, _ignoreLazyLoad, _factoryType) { PropertyType = prop.PropertyType, IsNullable = association.CanBeNull, Getter = GettersHandlers[mapperType][prop.Name], }; } else { Type listElementType = GetGenericType(prop.PropertyType); TableDescription colElementTableDescription = GetTableDescription(listElementType); // TODO Generate this instance using the CreateObjectMapperInstance method of fullMappingSchema propertiesMapping = new CollectionFullObjectMapper(_db, _factoryType) { PropertyType = listElementType, Getter = GettersHandlers[mapperType][prop.Name], TableName = colElementTableDescription.TableName, PropertyCollectionType = prop.PropertyType, }; if (mapper is FullObjectMapper) ((FullObjectMapper) mapper).ColParent = true; } if (association.ThisKey == null || association.ThisKey.Length == 0) association.ThisKey = new[] {primaryKeyMemberAccessor.Name}; bool isLazy = false; if (!_ignoreLazyLoad) { var lazy = GetLazyInstance(ma); // prop.GetCustomAttributes(typeof(LazyInstanceAttribute), true); if (lazy) { isLazy = true; mapper.ContainsLazyChild = true; // Getters lock (SetterHandlersLock) if (!GettersHandlers[mapperType].ContainsKey(primaryKeyMemberAccessor.Name)) { GettersHandlers[mapperType].Add(primaryKeyMemberAccessor.Name, primaryKeyMemberAccessor.GetValue); } } } propertiesMapping.Association = association; propertiesMapping.PropertyName = prop.Name; propertiesMapping.IsLazy = isLazy; propertiesMapping.Setter = SettersHandlers[mapperType][prop.Name]; if (propertiesMapping.IsLazy) { propertiesMapping.ParentKeyGetter = GettersHandlers[mapperType][primaryKeyMemberAccessor.Name]; } objectMappers.Add(propertiesMapping); } else { var mapIgnore = GetMapIgnore(ma); if (mapIgnore) continue; var mapField = GetMapField(ma); string columnName = mapField != null ? mapField.MapName : prop.Name; var map = new ValueMapper { PropertyName = prop.Name, PropertyType = prop.PropertyType, DataReaderIndex = startIndex, Setter = SettersHandlers[mapperType][prop.Name], TableName = tableDescription.TableName, ColumnName = columnName, }; var mapColumnName = map.GetColumnName(columnName); map.ColumnAlias = columnName == mapColumnName ? null : mapColumnName; mapper.PropertiesMapping.Add(map); var pkField = GetPrimaryKey(ma); if (pkField != null) mapper.DataReaderIndex = startIndex; startIndex++; } } foreach (IObjectMapper objMap in objectMappers) { #region Check mapping recursion IObjectMapper cel = mapper; while (cel != null) { if (mapper.PropertyType == objMap.PropertyType) continue; cel = (IObjectMapper) cel.ParentMapping; } #endregion objMap.ParentMapping = mapper; mapper.PropertiesMapping.Add(GetObjectMapper(objMap, ref startIndex, MappingSchema.GetObjectMapper(objMap.PropertyType).TypeAccessor)); } return mapper; } protected object LoadLazy(IMapper mapper, object proxy, Type parentType) { var lazyMapper = (ILazyMapper) mapper; object key = lazyMapper.ParentKeyGetter(proxy); var fullSqlQuery = new FullSqlQuery(_db, ignoreLazyLoad: true); object parentLoadFull = fullSqlQuery.SelectByKey(parentType, key); if (parentLoadFull == null) { object value = Activator.CreateInstance(mapper is CollectionFullObjectMapper ? (mapper as CollectionFullObjectMapper).PropertyCollectionType : mapper.PropertyType); return value; } var objectMapper = (IObjectMapper) mapper; return objectMapper.Getter(parentLoadFull); } private static Type GetGenericType(Type t) { if (t.IsGenericType) { Type[] at = t.GetGenericArguments(); return at.FirstOrDefault(); } return null; } #endregion } }