sexta-feira, 24 de julho de 2015

NHibernate - EntityVisitor

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;

namespace Lapuinka.Data
{
    public class EntityVisitor
    {
        protected readonly HashSet<IEntity> _entities;

        protected EntityVisitor()
        {
            _entities = new HashSet<IEntity>();
        }

        protected virtual IEntity Visit(IEntity entity)
        {
            return VisitEntity(entity, entity.GetEntityType());
        }

        protected virtual IEntity VisitEntity(IEntity entity, Type entityType)
        {
            if (entity == null) return null;
            if (_entities.Contains(entity)) return entity;

            _entities.Add(entity);

            foreach (var property in entityType.GetProperties())
            {
                VisitProperty(entity, property);
            }

            return entity;
        }

        protected virtual void VisitProperty(IEntity entity, PropertyInfo property)
        {
            if (!property.CanRead) return;
            if (property.GetCustomAttributes(typeof(XmlIgnoreAttribute), true).Length > 0) return;

            var propertyValue = property.GetValue(entity, null);

            if (propertyValue == null) return;

            switch (Type.GetTypeCode(property.PropertyType))
            {
                case TypeCode.Byte:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                case TypeCode.SByte:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                case TypeCode.Boolean:
                case TypeCode.Char:
                case TypeCode.String:
                case TypeCode.DateTime:
                    break;

                case TypeCode.Object:
                case TypeCode.Empty:
                case TypeCode.DBNull:
                    if (property.PropertyType == typeof(Guid))
                    {
                        break;
                    }

                    if (property.PropertyType.GetInterfaces().Any(x => x == typeof(IEntity)))
                    {
                        VisitEntity((IEntity)propertyValue, property.PropertyType);
                        break;
                    }

                    if (property.PropertyType.GetInterfaces().Any(x => x == typeof(IEnumerable)))
                    {
                        var elementType = property.PropertyType.GetGenericArguments()[0];

                        if (elementType.GetInterfaces().All(x => x != typeof(IEntity)))
                        {
                            break;
                        }

                        foreach (var item in (IEnumerable)propertyValue)
                        {
                            VisitEntity((IEntity)item, elementType);
                        }

                        break;
                    }

                    if (property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        break;
                    }

                    throw new NotSupportedException(
                        String.Format("PropertyType {0} is not supported", property.PropertyType.FullName)
                        );
            }
        }
    }

}
Postar um comentário