/// <summary>
        /// Tries to map a property on a DTO to a method on an entity
        /// </summary>
        /// <param name="entity">The entity</param>
        /// <param name="dto">The DTO</param>
        /// <param name="dtoProperty">The DTO property</param>
        /// <param name="mapNestedDtos">If true, all nested DTOs are mapped</param>
        protected virtual void TryMapToMethod(IAggregateEntity entity, ref object dto, PropertyInfo dtoProperty, bool mapNestedDtos = false)
        {
            var methods = GetMappableMethods(entity);

            var candidates = methods.Where
                             (
                _ => _.ReturnType.IsAssignableFrom(dtoProperty.PropertyType) ||
                _.ReturnType.ImplementsInterface(typeof(IAggregateEntity))
                             );

            foreach (var method in candidates)
            {
                var matches = method.Name.Contains(dtoProperty.Name);

                if (matches)
                {
                    var result      = default(object);
                    var success     = default(bool);
                    var isAggregate = false;

                    try
                    {
                        result  = method.Invoke(entity, null);
                        success = true;
                    }
                    catch (Exception ex)
                    {
                        // NOTE: we are ignoring errors when mapping to methods
                        success = false;

                        Debug.WriteLine($"Entity Mapping Error: {ex.Message}");
                    }

                    if (success)
                    {
                        if (result != null)
                        {
                            isAggregate = result.GetType().ImplementsInterface(typeof(IAggregateEntity));
                        }

                        if (isAggregate)
                        {
                            if (mapNestedDtos)
                            {
                                var childDto = Activator.CreateInstance(dtoProperty.PropertyType);

                                Map((IAggregateEntity)result, ref childDto, mapNestedDtos);

                                dtoProperty.SetValue(dto, childDto);
                            }
                        }
                        else
                        {
                            dtoProperty.SetValue(dto, result);
                        }
                    }
                }
            }
        }
예제 #2
0
        /// <summary>Determines if two IAggregateEntity instances are similar.</summary>
        /// <param name="first">The first IAggregateEntity</param>
        /// <param name="second">The second IAggregateEntity</param>
        /// <returns>
        /// <c>true</c> if the given IAggregateEntity instances are similar; otherwise, <c>false</c>.
        /// </returns>
        private static Similarity IsSimilarTo(this IAggregateEntity first, IAggregateEntity second)
        {
            var simResults = from e1 in first
                             from e2 in second
                             select e1.IsSimilarTo(e2);

            return(Similarity.FromRatio(simResults.Select(x => x.Boolean).PercentTrue() / 100));
        }
        /// <summary>
        /// Tries to map a property on an entity to a property on a DTO
        /// </summary>
        /// <param name="entity">The entity</param>
        /// <param name="dto">The DTO</param>
        /// <param name="entityProperty">The entity property</param>
        /// <param name="dtoProperty">The DTO property</param>
        /// <param name="mapNestedDtos">If true, all nested DTOs are mapped</param>
        protected virtual void TryMapProperty
        (
            IAggregateEntity entity,
            ref object dto,
            PropertyInfo entityProperty,
            PropertyInfo dtoProperty,
            bool mapNestedDtos
        )
        {
            var entityPropertyType = entityProperty.PropertyType;
            var dtoPropertyType    = dtoProperty.PropertyType;

            if (dtoPropertyType == entityPropertyType)
            {
                var entityPropertyValue = entityProperty.GetValue(entity);
                var configuration       = this.LocaleConfiguration;

                if (dtoPropertyType == typeof(DateTime))
                {
                    var date = (DateTime)entityPropertyValue;

                    entityPropertyValue = date.ToLocalTime(configuration);
                }

                if (dtoPropertyType == typeof(DateTime?))
                {
                    var date = (DateTime?)entityPropertyValue;

                    entityPropertyValue = date.ToLocalTime(configuration);
                }

                dtoProperty.SetValue(dto, entityPropertyValue);
            }
            else if (dtoPropertyType == typeof(string))
            {
                var entityPropertyValue = entityProperty.GetValue(entity);

                if (entityPropertyValue != null)
                {
                    dtoProperty.SetValue(dto, entityPropertyValue.ToString());
                }
                else
                {
                    dtoProperty.SetValue(dto, null);
                }
            }
            else if (mapNestedDtos)
            {
                MapNestedProperty(entity, ref dto, entityProperty, dtoProperty);
            }
        }
        /// <summary>
        /// Maps a single entity to a DTO
        /// </summary>
        /// <param name="entity">The entity to map</param>
        /// <param name="dto">The DTO to map to</param>
        /// <param name="mapNestedDtos">If true, all nested DTOs are mapped</param>
        /// <returns>The mapped DTO</returns>
        protected virtual void Map(IAggregateEntity entity, ref object dto, bool mapNestedDtos)
        {
            if (entity == null)
            {
                dto = null;

                return;
            }
            else
            {
                var entityProperties = GetMappableProperties(entity);
                var dtoProperties    = GetMappableProperties(dto);
                var mappedNames      = new List <string>();

                foreach (var dtoProperty in dtoProperties)
                {
                    var isKeyProperty = dtoProperty.Name.Equals("Key", StringComparison.InvariantCultureIgnoreCase);

                    if (isKeyProperty)
                    {
                        dtoProperty.SetValue(dto, entity.LookupKey);
                    }
                    else
                    {
                        var alreadyMapped = mappedNames.Contains(dtoProperty.Name);

                        if (alreadyMapped)
                        {
                            continue;
                        }

                        var entityProperty = entityProperties.FirstOrDefault(_ => _.Name == dtoProperty.Name);

                        if (entityProperty != null)
                        {
                            TryMapProperty(entity, ref dto, entityProperty, dtoProperty, mapNestedDtos);
                        }
                        else
                        {
                            TryMapToMethod(entity, ref dto, dtoProperty, mapNestedDtos);
                        }

                        mappedNames.Add(dtoProperty.Name);
                    }
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Tries to map a property on a DTO to a property on an entity
        /// </summary>
        /// <param name="entity">The entity</param>
        /// <param name="dto">The DTO</param>
        /// <param name="entityProperty">The entity property</param>
        /// <param name="dtoProperty">The DTO property</param>
        /// <param name="mapNestedDtos">If true, all nested DTOs are mapped</param>
        protected virtual void TryMapProperty
        (
            IAggregateEntity entity,
            ref object dto,
            PropertyInfo entityProperty,
            PropertyInfo dtoProperty,
            bool mapNestedDtos
        )
        {
            var dtoPropertyType = dtoProperty.PropertyType;

            var entityPropertyValue = entityProperty.GetValue
                                      (
                entity
                                      );

            if (dtoPropertyType == entityProperty.PropertyType)
            {
                if (dtoPropertyType == typeof(DateTime))
                {
                    var date = (DateTime)entityPropertyValue;

                    entityPropertyValue = date.ToLocalTime
                                          (
                        this.LocaleConfiguration
                                          );
                }

                if (dtoPropertyType == typeof(DateTime?))
                {
                    var date = (DateTime?)entityPropertyValue;

                    entityPropertyValue = date.ToLocalTime
                                          (
                        this.LocaleConfiguration
                                          );
                }

                dtoProperty.SetValue
                (
                    dto,
                    entityPropertyValue
                );
            }
            else if (dtoPropertyType == typeof(string))
            {
                if (entityPropertyValue != null)
                {
                    dtoProperty.SetValue
                    (
                        dto,
                        entityPropertyValue.ToString()
                    );
                }
            }
            else if (mapNestedDtos)
            {
                var isList =
                    (
                        dtoPropertyType.IsGenericType &&
                        dtoPropertyType.GetGenericTypeDefinition() == typeof(List <>)
                    );

                if (isList)
                {
                    var dtoListType    = dtoPropertyType.GetGenericArguments()[0];
                    var entityListType = entityProperty.PropertyType.GetGenericArguments()[0];

                    var isValidDto = IsValidDtoType
                                     (
                        dtoListType,
                        entityListType
                                     );

                    if (false == isValidDto)
                    {
                        throw new InvalidOperationException
                              (
                                  "The list type is not a valid DTO."
                              );
                    }

                    var isValidEntityCollection = entityListType.ImplementsInterface
                                                  (
                        typeof(IAggregateEntity)
                                                  );

                    if (false == isValidEntityCollection)
                    {
                        var typeName     = entityListType.Name;
                        var propertyName = entityProperty.Name;

                        throw new InvalidOperationException
                              (
                                  $"{typeName} on {propertyName} does not implement IAggregateEntity."
                              );
                    }

                    var dtoList = (IList)Activator.CreateInstance
                                  (
                        dtoPropertyType
                                  );

                    var entityCollection = (IEnumerable)entityProperty.GetValue
                                           (
                        entity
                                           );

                    foreach (IAggregateEntity childEntity in entityCollection)
                    {
                        var childDto = Activator.CreateInstance
                                       (
                            dtoListType
                                       );

                        Map(childEntity, ref childDto, mapNestedDtos);

                        dtoList.Add(childDto);
                    }

                    dtoProperty.SetValue(dto, dtoList);
                }
                else
                {
                    var isValidDto = IsValidDtoType
                                     (
                        dtoPropertyType,
                        entityProperty.PropertyType
                                     );

                    if (isValidDto)
                    {
                        var childEntity = (IAggregateEntity)entityProperty.GetValue
                                          (
                            entity
                                          );

                        var childDto = Activator.CreateInstance
                                       (
                            dtoPropertyType
                                       );

                        Map(childEntity, ref childDto, mapNestedDtos);

                        dtoProperty.SetValue(dto, childDto);
                    }
                    else
                    {
                        throw new InvalidOperationException
                              (
                                  $"The property {dtoProperty.Name} could not be mapped."
                              );
                    }
                }
            }
        }
        /// <summary>
        /// Maps a nested property on an entity to a property on a DTO
        /// </summary>
        /// <param name="entity">The entity</param>
        /// <param name="dto">The DTO</param>
        /// <param name="entityProperty">The entity property</param>
        /// <param name="dtoProperty">The DTO property</param>
        protected virtual void MapNestedProperty
        (
            IAggregateEntity entity,
            ref object dto,
            PropertyInfo entityProperty,
            PropertyInfo dtoProperty
        )
        {
            var entityPropertyType = entityProperty.PropertyType;
            var dtoPropertyType    = dtoProperty.PropertyType;

            var isList = (dtoPropertyType.IsGenericType && dtoPropertyType.GetGenericTypeDefinition() == typeof(List <>));

            if (isList)
            {
                var dtoListType    = dtoPropertyType.GetGenericArguments()[0];
                var entityListType = entityPropertyType.GetGenericArguments()[0];
                var isValidDto     = IsValidDtoType(dtoListType, entityListType);

                if (false == isValidDto)
                {
                    throw new InvalidOperationException("The list type is not a valid DTO.");
                }

                var isValidEntityCollection = entityListType.ImplementsInterface(typeof(IAggregateEntity));

                if (false == isValidEntityCollection)
                {
                    var typeName     = entityListType.Name;
                    var propertyName = entityProperty.Name;

                    throw new InvalidOperationException
                          (
                              $"{typeName} on {propertyName} does not implement {nameof(IAggregateEntity)}."
                          );
                }

                var dtoList          = (IList)Activator.CreateInstance(dtoPropertyType);
                var entityCollection = (IEnumerable)entityProperty.GetValue(entity);

                foreach (IAggregateEntity childEntity in entityCollection)
                {
                    var childDto = Activator.CreateInstance(dtoListType);

                    Map(childEntity, ref childDto, true);

                    dtoList.Add(childDto);
                }

                dtoProperty.SetValue(dto, dtoList);
            }
            else
            {
                var isValidDto = IsValidDtoType(dtoPropertyType, entityPropertyType);

                if (isValidDto)
                {
                    var childEntity = (IAggregateEntity)entityProperty.GetValue(entity);
                    var childDto    = Activator.CreateInstance(dtoPropertyType);

                    Map(childEntity, ref childDto, true);

                    dtoProperty.SetValue(dto, childDto);
                }
                else
                {
                    throw new InvalidOperationException
                          (
                              $"Property '{dtoProperty.Name}' could not be mapped. " +
                              $"Type {dtoPropertyType.Name} cannot be converted to " +
                              $"{entityPropertyType.Name}."
                          );
                }
            }
        }