Created
September 6, 2017 10:11
-
-
Save Alexei000/3f6af8b3c20627b836cee5d5b29ac9da to your computer and use it in GitHub Desktop.
Object list fetch - mapping service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
using AutoMapper; | |
using Common.Web; | |
using MdwAutomaticTesting.Models; | |
namespace MdwAutomaticTesting.Services | |
{ | |
public class MappingService : IMappingService | |
{ | |
#region Properties | |
public IMapper Mapper { get; } | |
public IScopedDataAccess DataAccess { get; } | |
#endregion | |
#region Constructor | |
public MappingService(IScopedDataAccess dataAccess) | |
{ | |
DataAccess = dataAccess; | |
var config = new MapperConfiguration(cfg => | |
{ | |
// mappings come here | |
}; | |
Mapper = config.CreateMapper(); | |
} | |
#endregion | |
#region Private methods | |
private void GetTypesMapsInfo<TSrc>(IList<PropertyInfo> standardListItemAttrProps, | |
out Dictionary<string, Type> standardListPropToModelType, out Dictionary<string, PropertyInfo> sourcePropMap, out Dictionary<string, IRepository> reposMap) | |
{ | |
var srcProps = typeof(TSrc).GetProperties(); | |
standardListPropToModelType = standardListItemAttrProps.ToDictionary(pi => pi.Name, pi => typeof(IList).IsAssignableFrom(pi.PropertyType) ? | |
pi.PropertyType.GenericTypeArguments[0].GetGenericArguments()[0]: | |
pi.PropertyType.GenericTypeArguments[0]); | |
sourcePropMap = standardListItemAttrProps.ToDictionary(pi => pi.Name, pi => srcProps.FirstOrDefault(srcPi => srcPi.Name == pi.Name)); | |
var standardListPropToModelTypeBuffer = standardListPropToModelType; | |
reposMap = standardListItemAttrProps.ToDictionary(pi => pi.Name, pi => DataAccess.GetRepository(standardListPropToModelTypeBuffer[pi.Name])); | |
} | |
private void PopulateStandardListItem(int key, StandardListItem destItem, Type modelType, PropertyInfo stdItemProp, IRepository repo) | |
{ | |
// undefined value cannot be found within a repository, setting unspecified | |
if (key.IsUndefined()) | |
{ | |
// ReSharper disable once PossibleNullReferenceException | |
destItem.Key = Common.Web.Constants.Controls.NullId; | |
destItem.Value = Common.Web.Constants.Controls.NullStr; | |
return; | |
} | |
// ReSharper disable once PossibleNullReferenceException | |
destItem.Key = key; | |
var standardListItem = repo.GetGeneric(key) as IStandardListItem; | |
if (standardListItem == null) | |
throw new ArgumentException($"Property {stdItemProp.Name} of type {modelType} must implement IStandardListItem"); | |
destItem.Value = standardListItem.Value; | |
destItem.IsEnabled = standardListItem.IsEnabled; | |
} | |
private StandardListItem GetEmptyStandardListItem(Type modelType) | |
{ | |
var genericClass = typeof(StandardListItem<>); | |
var constructedClass = genericClass.MakeGenericType(modelType); | |
var newStandardListItem = Activator.CreateInstance(constructedClass) as StandardListItem; | |
return newStandardListItem; | |
} | |
private void TransferSingleStandardListItemValue<TSrc, TDest>(PropertyInfo srcPropInfo, PropertyInfo stdItemProp, Type modelType, TSrc srcEnt, TDest destEnt, IRepository repo) | |
{ | |
// if destination is not initialized, initializing it | |
var destItem = stdItemProp.GetValue(destEnt) as StandardListItem; | |
if (destItem == null) | |
{ | |
var newStandardListItem = GetEmptyStandardListItem(modelType); | |
stdItemProp.SetValue(destEnt, newStandardListItem); | |
destItem = newStandardListItem; | |
} | |
// if source property is not an integer, but a StandardListItem, direct copy the information | |
var srcObjValue = srcPropInfo.GetValue(srcEnt, index: null); | |
if (srcObjValue is int) | |
{ | |
int key = Convert.ToInt32(srcObjValue); | |
PopulateStandardListItem(key, destItem, modelType, stdItemProp, repo); | |
} | |
else if (srcObjValue is StandardListItem) | |
{ | |
var srcStdItem = srcObjValue as StandardListItem; | |
destItem.Key = srcStdItem.Key; | |
destItem.Value = srcStdItem.Value; | |
destItem.IsEnabled = srcStdItem.IsEnabled; | |
} | |
// other types will simply not be mapped | |
} | |
private void TransferListOfStandardListItemValue<TSrc, TDest>(PropertyInfo srcPropInfo, PropertyInfo stdItemProp, Type modelType, TSrc srcEnt, TDest destEnt, IRepository repo) | |
{ | |
var destList = stdItemProp.GetValue(destEnt) as IList; | |
if (destList == null) | |
{ | |
var genericClass = typeof(StandardListItem<>); | |
var constructedClass = genericClass.MakeGenericType(modelType); | |
var listGenericType = typeof(List<>); | |
var listClass = listGenericType.MakeGenericType(constructedClass); | |
var newListOfStandardListItems = Activator.CreateInstance(listClass) as IList; | |
stdItemProp.SetValue(destEnt, newListOfStandardListItems); | |
destList = newListOfStandardListItems; | |
} | |
var srcList = srcPropInfo.GetValue(srcEnt, null) as IList; | |
if (srcList == null) | |
return; | |
foreach (int srcItem in srcList) | |
{ | |
var newStandardListItem = GetEmptyStandardListItem(modelType); | |
// ReSharper disable once PossibleNullReferenceException | |
destList.Add(newStandardListItem); | |
PopulateStandardListItem(srcItem, newStandardListItem, modelType, stdItemProp, repo); | |
} | |
} | |
private void MapEx<TSrc, TDest>(TSrc srcEnt, TDest destEnt, | |
IEnumerable<PropertyInfo> standardListItemAttrProps, IReadOnlyDictionary<string, Type> standardListPropToModelType, IReadOnlyDictionary<string, PropertyInfo> sourcePropMap, IReadOnlyDictionary<string, IRepository> reposMap) | |
{ | |
if (destEnt == null) | |
return; | |
foreach (var stdItemProp in standardListItemAttrProps) | |
{ | |
var srcPropInfo = sourcePropMap[stdItemProp.Name]; | |
if (srcPropInfo == null) | |
continue; | |
var modelType = standardListPropToModelType[stdItemProp.Name]; | |
var propIsList = typeof(IList).IsAssignableFrom(stdItemProp.PropertyType); | |
var repo = reposMap[stdItemProp.Name]; | |
if (!propIsList) | |
TransferSingleStandardListItemValue(srcPropInfo, stdItemProp, modelType, srcEnt, destEnt, repo); | |
else | |
TransferListOfStandardListItemValue(srcPropInfo, stdItemProp, modelType, srcEnt, destEnt, repo); | |
} | |
} | |
#endregion | |
public IList<TDest> MapEx<TSrc, TDest>(IList<TSrc> srcList, IMapper customMapper = null) where TDest : new() | |
{ | |
var actualMapper = customMapper ?? Mapper; | |
var result = actualMapper.Map<List<TDest>>(srcList); | |
// mapping standard item lists (marked with StandardListItemMappingInfoAttribute) | |
var standardListItemAttrProps = typeof(TDest).GetProperties().Where(pi => pi.GetCustomAttributes(typeof(StandardListItemMappingInfoAttribute), inherit: true).Length > 0).ToList(); | |
if (standardListItemAttrProps.Count <= 0) | |
return result; | |
Dictionary<string, Type> standardListPropToModelType; | |
Dictionary<string, PropertyInfo> sourcePropMap; | |
Dictionary<string, IRepository> reposMap; | |
GetTypesMapsInfo<TSrc>(standardListItemAttrProps, out standardListPropToModelType, out sourcePropMap, out reposMap); | |
for (int index = 0; index < srcList.Count; index ++) | |
{ | |
var srcEnt = srcList[index]; | |
var destEnt = result[index]; | |
MapEx(srcEnt, destEnt, standardListItemAttrProps, standardListPropToModelType, sourcePropMap, reposMap); | |
} | |
return result; | |
} | |
public void MapEx<TSrc, TDest>(TSrc src, TDest result, IMapper customMapper = null) | |
{ | |
var actualMapper = customMapper ?? Mapper; | |
actualMapper.Map(src, result); | |
// sanity check to avoid transferring lists to this overload | |
if (typeof(IList).IsAssignableFrom(typeof(TSrc))) | |
throw new ArgumentException($"{nameof(src)} should not be a list"); | |
// mapping standard item lists (marked with StandardListItemMappingInfoAttribute) | |
var standardListItemAttrProps = typeof(TDest).GetProperties().Where(pi => pi.GetCustomAttributes(typeof(StandardListItemMappingInfoAttribute), inherit: true).Length > 0).ToList(); | |
if (standardListItemAttrProps.Count <= 0) | |
return; | |
Dictionary<string, Type> standardListPropToModelType; | |
Dictionary<string, PropertyInfo> sourcePropMap; | |
Dictionary<string, IRepository> reposMap; | |
GetTypesMapsInfo<TSrc>(standardListItemAttrProps, out standardListPropToModelType, out sourcePropMap, out reposMap); | |
MapEx(src, result, standardListItemAttrProps, standardListPropToModelType, sourcePropMap, reposMap); | |
} | |
public TDest MapEx<TSrc, TDest>(TSrc src, IMapper customMapper = null) where TDest : new() | |
{ | |
var actualMapper = customMapper ?? Mapper; | |
var result = actualMapper.Map<TDest>(src); | |
MapEx(src, result, actualMapper); | |
return result; | |
} | |
public TListTotalDest MapListWithTotalCountModels<TSrc, TDest, TListTotalSrc, TListTotalDest>(TListTotalSrc src, IMapper customMapper = null) where TDest : new() | |
where TListTotalSrc : ListWithTotalCount<TSrc> | |
where TListTotalDest : ListWithTotalCount<TDest> | |
{ | |
var mappedList = MapEx<TSrc, TDest>(src.Items, customMapper); | |
var result = Activator.CreateInstance<TListTotalDest>(); | |
result.TotalCount = src.TotalCount; | |
result.Items = mappedList; | |
return result; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment