diff Extensions/JointureAddOn/Mapping/FullObjectMapper.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Extensions/JointureAddOn/Mapping/FullObjectMapper.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,354 @@
+#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
+    }
+}
\ No newline at end of file