예제 #1
0
        /// <summary>
        /// Sets the <see cref="IPropertyMapperConverter{TSrceProperty, TDestProperty}"/> (used where a specific source and destination type conversion is required).
        /// </summary>
        /// <typeparam name="TDestProperty">The destination property <see cref="Type"/>.</typeparam>
        /// <param name="converter">The <see cref="IPropertyMapperConverter{TSrceProperty, TDestProperty}"/>.</param>
        /// <returns>The <see cref="PropertyMapperCustomBase{TSrce, TSrceProperty}"/>.</returns>
        /// <remarks>The <see cref="Mapper"/> and <see cref="Converter"/> are mutually exclusive.</remarks>
        public PropertyMapperCustomBase <TSrce, TSrceProperty> SetConverter <TDestProperty>(IPropertyMapperConverter <TSrceProperty, TDestProperty> converter)
        {
            if (Mapper != null && converter != null)
            {
                throw new MapperException("The Mapper and Converter cannot be both set; only one is permissible.");
            }

            Converter = converter;
            return(this);
        }
예제 #2
0
        /// <summary>
        /// Sets the <see cref="Converter"/>.
        /// </summary>
        /// <param name="converter">The <see cref="IPropertyMapperConverter"/>.</param>
        void IPropertyMapperBase.SetConverter(IPropertyMapperConverter converter)
        {
            if (Mapper != null && converter != null)
            {
                throw new MapperException("The Mapper and Converter cannot be both set; only one is permissible.");
            }

            if (converter != null && converter.SrceType != typeof(TSrceProperty))
            {
                throw new MapperException($"The PropertyMapper SrceType '{typeof(TSrceProperty).Name}' and Converter SrceType '{converter.SrceType.Name}' must match.");
            }

            Converter = converter;
        }
예제 #3
0
        /// <summary>
        /// Gets from cache (or creates and adds to cache) the <see cref="IODataMapper"/> (with option to merge alternate property configuration).
        /// </summary>
        private static IODataMapper GetOrCreateMapper(Type type, Dictionary <string, MemberInfo> altProps, string overrideEntityName)
        {
            if (_cache.TryGetValue(type, out IODataMapper map))
            {
                return(map);
            }

            lock (_lock)
            {
                if (_cache.TryGetValue(type, out map))
                {
                    return(map);
                }

                if (!type.IsClass)
                {
                    throw new MapperException($"Type '{type.Name}' must be a class for auto-mapping.");
                }

                var mea = type.GetCustomAttributes(typeof(MapperEntityAttribute), true).OfType <MapperEntityAttribute>().FirstOrDefault();
                map = (IODataMapper)Activator.CreateInstance(typeof(ODataMapper <>).MakeGenericType(type), (overrideEntityName ?? mea?.Name) ?? type.Name);
                var    pe            = Expression.Parameter(type, "x");
                string dname         = null;
                var    hasProperties = false;

                MapperPropertyAttribute mpa = null;

                foreach (var p in TypeReflector.GetProperties(type))
                {
                    // Do not auto-map where the Ignore attribute has been specified.
                    if (p.GetCustomAttributes(typeof(MapperIgnoreAttribute), true).OfType <MapperIgnoreAttribute>().FirstOrDefault() != null)
                    {
                        continue;
                    }

                    // Get property merge config.
                    if (altProps == null)
                    {
                        mpa   = p.GetCustomAttributes(typeof(MapperPropertyAttribute), true).OfType <MapperPropertyAttribute>().FirstOrDefault();
                        dname = mpa?.Name;
                    }
                    else
                    {
                        if (!altProps.TryGetValue(p.Name, out MemberInfo alt))
                        {
                            throw new InvalidOperationException($"Type '{type.Name}' Property '{p.Name}' does not have an alternative property configuration specified.");
                        }

                        // Do not auto-map where the Ignore attribute has been specified.
                        if (alt.GetCustomAttributes(typeof(MapperIgnoreAttribute), true).OfType <MapperIgnoreAttribute>().FirstOrDefault() != null)
                        {
                            continue;
                        }

                        mpa   = alt.GetCustomAttributes(typeof(MapperPropertyAttribute), true).OfType <MapperPropertyAttribute>().FirstOrDefault();
                        dname = mpa?.Name ?? alt.Name;
                    }

                    // Create the lambda expression for the property and add to the mapper.
                    hasProperties = true;

                    var lex  = Expression.Lambda(Expression.Property(pe, p.Name), pe);
                    var pmap = (IODataPropertyMapper)map.GetType()
                               .GetMethod("Property", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
                               .MakeGenericMethod(p.PropertyType)
                               .Invoke(map, new object[] { lex, dname, mpa == null ? OperationTypes.Any : mpa.OperationTypes });

                    if (mpa == null)
                    {
                        continue;
                    }

                    // Apply auto-map Property attribute IsUnique configuration.
                    if (mpa.IsUniqueKey)
                    {
                        pmap.SetUniqueKey(mpa.IsUniqueKeyAutoGeneratedOnCreate);
                    }

                    // Apply auto-map Property attribute ConverterType configuration.
                    if (mpa.ConverterType != null)
                    {
                        if (!typeof(IPropertyMapperConverter).IsAssignableFrom(mpa.ConverterType))
                        {
                            throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with ConverterType set to '{mpa.ConverterType.Name}' which does not implement 'IPropertyMapperConverter'.");
                        }

                        IPropertyMapperConverter pmc = null;
                        var pdef = mpa.ConverterType.GetProperty("Default", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static);
                        if (pdef == null)
                        {
                            if (mpa.ConverterType.GetConstructor(Type.EmptyTypes) == null)
                            {
                                throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with ConverterType set to '{mpa.ConverterType.Name}' does not have a static 'Default' property or default constructor.");
                            }

                            pmc = (IPropertyMapperConverter)Activator.CreateInstance(mpa.ConverterType);
                        }
                        else
                        {
                            pmc = (IPropertyMapperConverter)pdef.GetValue(null);
                        }

                        pmap.SetConverter(pmc);
                        continue;
                    }

                    // Apply auto-map Property attribute MapperType configuration for complex types.
                    if (pmap.IsSrceComplexType)
                    {
                        IEntityMapperBase em = null;
                        if (mpa.MapperType == null)
                        {
                            em = GetMapper(pmap.SrceComplexTypeReflector.ItemType);
                        }
                        else
                        {
                            if (!typeof(IEntityMapperBase).IsAssignableFrom(mpa.MapperType))
                            {
                                throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.MapperType.Name}' which does not implement 'IEntityMapper'.");
                            }

                            var mdef = mpa.MapperType.GetProperty("Default", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static);
                            if (mdef == null)
                            {
                                if (mpa.ConverterType.GetConstructor(Type.EmptyTypes) == null)
                                {
                                    throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.MapperType.Name}' does not have a static 'Default' property or default constructor.");
                                }

                                em = (IEntityMapperBase)Activator.CreateInstance(mpa.MapperType);
                            }
                            else
                            {
                                em = (IEntityMapperBase)mdef.GetValue(null);
                            }
                        }

                        if (em != null)
                        {
                            pmap.SetMapper(em);
                        }
                    }
                    else if (mpa.MapperType != null)
                    {
                        throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.ConverterType.Name}' although the property is not a complex type.");
                    }
                }

                if (!hasProperties)
                {
                    throw new MapperException($"AutoMapper has found no properties for Type '{type.Name}' that it is able to auto-map.");
                }

                _cache.Add(type, map);
                return(map);
            }
        }
예제 #4
0
 /// <summary>
 /// Sets the <see cref="IPropertyMapperConverter{TSrceProperty, TDestProperty}"/> (used where a specific source and destination type conversion is required).
 /// </summary>
 /// <typeparam name="TDestProperty">The destination property <see cref="Type"/>.</typeparam>
 /// <param name="converter">The <see cref="IPropertyMapperConverter{TSrceProperty, TDestProperty}"/>.</param>
 /// <returns>The <see cref="PropertyMapperCustomBase{TSrce, TSrceProperty}"/>.</returns>
 public new ODataPropertyMapper<TSrce, TSrceProperty> SetConverter<TDestProperty>(IPropertyMapperConverter<TSrceProperty, TDestProperty> converter)
 {
     base.SetConverter(converter);
     return this;
 }
예제 #5
0
        /// <summary>
        /// Automatically map commonly named properties.
        /// </summary>
        private void AutomagicallyMap(string[] ignoreSrceProperties)
        {
            MapperPropertyAttribute mpa = null;

            foreach (var sp in SrceType.GetProperties(BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.Instance))
            {
                // Do not auto-map where ignore has been specified.
                if (ignoreSrceProperties.Contains(sp.Name))
                {
                    continue;
                }

                if (sp.GetCustomAttributes(typeof(MapperIgnoreAttribute), true).OfType <MapperIgnoreAttribute>().FirstOrDefault() != null)
                {
                    continue;
                }

                // Find corresponding property.
                mpa = sp.GetCustomAttributes(typeof(MapperPropertyAttribute), true).OfType <MapperPropertyAttribute>().FirstOrDefault();
                var dname = mpa == null || string.IsNullOrEmpty(mpa.Name) ? sp.Name : mpa.Name;
                var dp    = DestType.GetProperty(dname, BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.Instance);
                if (dp == null)
                {
                    if (mpa != null)
                    {
                        throw new InvalidOperationException($"Type '{SrceType.Name}' Property '{sp.Name}' has 'MapperPropertyAttribute' with Name set to '{dname}' which does not exist for destination Type '{DestType.Name}'.");
                    }

                    continue;
                }

                // Create the lambda expressions for the property and add to the mapper.
                var spe  = Expression.Parameter(SrceType, "x");
                var sex  = Expression.Lambda(Expression.Property(spe, sp.Name), spe);
                var dpe  = Expression.Parameter(DestType, "x");
                var dex  = Expression.Lambda(Expression.Property(dpe, dname), dpe);
                var pmap = (IPropertyMapper <TSrce, TDest>) typeof(EntityMapper <TSrce, TDest>)
                           .GetMethod("PropertySrceAndDest", BindingFlags.NonPublic | BindingFlags.Instance)
                           .MakeGenericMethod(new Type[] { sp.PropertyType, dp.PropertyType })
                           .Invoke(this, new object[] { sex, dex });

                if (mpa == null)
                {
                    continue;
                }

                // Apply auto-map Property attribute IsUnique configuration.
                if (mpa.IsUniqueKey)
                {
                    pmap.SetUniqueKey(mpa.IsUniqueKeyAutoGeneratedOnCreate);
                }

                // Apply auto-map Property attribute ConverterType configuration.
                if (mpa.ConverterType != null)
                {
                    if (!typeof(IPropertyMapperConverter).IsAssignableFrom(mpa.ConverterType))
                    {
                        throw new MapperException($"Type '{SrceType.Name}' Property '{sp.Name}' has 'MapperPropertyAttribute' with ConverterType set to '{mpa.ConverterType.Name}' which does not implement 'IPropertyMapperConverter'.");
                    }

                    IPropertyMapperConverter pmc = null;
                    var pdef = mpa.ConverterType.GetProperty("Default", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static);
                    if (pdef == null)
                    {
                        if (mpa.ConverterType.GetConstructor(Type.EmptyTypes) == null)
                        {
                            throw new MapperException($"Type '{SrceType.Name}' Property '{sp.Name}' has 'MapperPropertyAttribute' with ConverterType set to '{mpa.ConverterType.Name}' does not have a static 'Default' property or default constructor.");
                        }

                        pmc = (IPropertyMapperConverter)Activator.CreateInstance(mpa.ConverterType);
                    }
                    else
                    {
                        pmc = (IPropertyMapperConverter)pdef.GetValue(null);
                    }

                    pmap.SetConverter(pmc);
                    continue;
                }

                // Apply auto-map Property attribute MapperType configuration for complex types.
                if (pmap.IsSrceComplexType)
                {
                    IEntityMapperBase em = null;
                    if (mpa.MapperType != null)
                    {
                        if (!typeof(IEntityMapperBase).IsAssignableFrom(mpa.MapperType))
                        {
                            throw new MapperException($"Type '{SrceType.Name}' Property '{sp.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.MapperType.Name}' which does not implement 'IEntityMapper'.");
                        }

                        var mdef = mpa.MapperType.GetProperty("Default", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static);
                        if (mdef == null)
                        {
                            if (mpa.ConverterType.GetConstructor(Type.EmptyTypes) == null)
                            {
                                throw new MapperException($"Type '{SrceType.Name}' Property '{sp.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.MapperType.Name}' does not have a static 'Default' property or default constructor.");
                            }

                            em = (IEntityMapperBase)Activator.CreateInstance(mpa.MapperType);
                        }
                        else
                        {
                            em = (IEntityMapperBase)mdef.GetValue(null);
                        }
                    }

                    if (em != null)
                    {
                        pmap.SetMapper(em);
                    }
                }
                else if (mpa.MapperType != null)
                {
                    throw new MapperException($"Type '{SrceType.Name}' Property '{sp.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.ConverterType.Name}' although the property is not a complex type.");
                }
            }
        }