/// <summary> /// Inherits the properties from the selected <paramref name="inheritMapper"/>. /// </summary> /// <param name="inheritMapper">The <see cref="IDatabaseMapper"/> to inherit from.</param> public void InheritPropertiesFrom <T>(IDatabaseMapper <T> inheritMapper) where T : class, new() { if (inheritMapper == null) { throw new ArgumentNullException(nameof(inheritMapper)); } if (!SrceType.GetTypeInfo().IsSubclassOf(typeof(T))) { throw new ArgumentException($"Type {typeof(T).Name} must inherit from {SrceType.Name}."); } var pe = Expression.Parameter(SrceType, "x"); var type = typeof(DatabaseMapper <>).MakeGenericType(SrceType); foreach (var p in inheritMapper.Mappings.OfType <IDatabasePropertyMapper>()) { var lex = Expression.Lambda(Expression.Property(pe, p.SrcePropertyName), pe); var pmap = (IDatabasePropertyMapper)type .GetMethod("Property", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) .MakeGenericMethod(p.SrcePropertyType) .Invoke(this, new object[] { lex, p.DestPropertyName, p.OperationTypes }); if (p.IsUniqueKey) { pmap.SetUniqueKey(p.IsUniqueKeyAutoGeneratedOnCreate); } pmap.DestDbType = p.DestDbType; pmap.SetConverter(p.Converter); pmap.SetMapper(p.Mapper); } }
/// <summary> /// Initialises a new instance of the <see cref="ODataMapper{TSrce}"/> class. /// </summary> /// <param name="odataEntityName">The <b>OData</b> entity name as represented within the URL.</param> public ODataMapper(string odataEntityName) { ODataEntityName = string.IsNullOrEmpty(odataEntityName) ? throw new ArgumentNullException(nameof(odataEntityName)) : odataEntityName; if (typeof(IETag).IsAssignableFrom(typeof(TSrce))) { Property(x => ((IETag)x).ETag, ODataETagPropertyName).MapSrceToDestWhen((v) => false); } _hasDefaultCtor = SrceType.GetConstructor(Type.EmptyTypes) != null; if (!_hasDefaultCtor) { // This is required to support the likes of compiler generated Types when using LINQ queries. _orderedProperties = SrceType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(x => x.Name).ToArray(); if (SrceType.GetConstructors().Where(x => x.GetParameters().Length == _orderedProperties.Length).Count() == 0) { throw new MapperException($"Type {SrceType.Name} does not have default constructor, or a constructor that accepts all properties; unable to determine constructor."); } } }
/// <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."); } } }