gpt4 book ai didi

c# - ValueInjector Stack Overflow 映射实体与父实体

转载 作者:行者123 更新时间:2023-11-30 12:31:23 26 4
gpt4 key购买 nike

我正在使用 ValueInjecter 来处理将我的 POCO 实体映射到我的 DTO 实体。我一直在用Automapper Simulation作为我的主要映射器。这使我可以像这样简单地编写一个映射:

var entity = GetEntityFromDatabase();
var dto = Mapper.Map<Entity, EntityDTO>(entity);

这一直很好用,直到我需要从我的数据库中获取具有父子关系的实体。问题是我一直在使用的这段代码将递归地遍历所有属性。如果我有一个看起来像这样的 POCO,

public class Entity {
public Guid Id {get; set;}
public Entity Parent {get; set;}
public IEnumerable<Entity> Children {get; set;}
}

我的代码将在无限循环中爆炸,试图映射循环引用。我想继续使用 Automapper Simulation 源作为我的主要映射器,但我一直在想办法解决我的问题。任何帮助将不胜感激!

最佳答案

我相信我通过更改 Automapper Simulation Mapper.cs 文件解决了这个问题。我在递归上实现了一个深度,如果我超过那个深度,我将对象设置为一个已经创建的对象。我确信这可以改进,但是,嘿,它现在有效!

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Omu.ValueInjecter;

namespace MySystem.Services.Mapping
{
// the static mapper class
public static class Mapper
{
private static IList<ObjectContainer> _objects;

//map source to an existing target
public static TTarget Map<TSource, TTarget>(TSource source, TTarget target)
{
target = MapperFactory.GetMapper<TSource, TTarget>().Map(source, target);
return target;
}

//create a new target and map source on it
public static TTarget Map<TSource, TTarget>(TSource source)
{
_objects = new List<ObjectContainer>();
var target = (TTarget)Creator.Create(typeof(TTarget));
var obj = MapperFactory.GetMapper<TSource, TTarget>().Map(source, target);
_objects.Add(new ObjectContainer()
{
original = source,
converted = obj
});
return obj;
}

public static object Map(object source, object target, Type sourceType, Type targetType)
{
target = target ?? Creator.Create(targetType);
var getMapper = typeof(MapperFactory).GetMethod("GetMapper").MakeGenericMethod(sourceType, targetType);
var mapper = getMapper.Invoke(null, null);
var map = mapper.GetType().GetMethod("Map");
var obj = map.Invoke(mapper, new[] { source, target });
_objects.Add(new ObjectContainer()
{
original = source,
converted = obj
});
return obj;
}

public static object MapFinal(object source, object target, Type sourceType, Type targetType)
{
foreach (var obj in _objects)
{
if (source.Equals(obj.original))
{
return obj.converted;
}
}
return null;
}
}

public class ObjectContainer
{
public object original { get; set; }
public object converted { get; set; }
}

public static class MapperFactory
{
private static readonly IDictionary<Type, object> Mappers = new Dictionary<Type, object>();

public static ITypeMapper<TSource, TTarget> GetMapper<TSource, TTarget>()
{
//if we have a specified TypeMapper for <TSource,Target> return it
if (Mappers.ContainsKey(typeof(ITypeMapper<TSource, TTarget>)))
return Mappers[typeof(ITypeMapper<TSource, TTarget>)] as ITypeMapper<TSource, TTarget>;

//if both Source and Target types are Enumerables return new EnumerableTypeMapper<TSource,TTarget>()
if (typeof(TSource).IsEnumerable() && typeof(TTarget).IsEnumerable())
{
return (ITypeMapper<TSource, TTarget>)Activator.CreateInstance(typeof(EnumerableTypeMapper<,>).MakeGenericType(typeof(TSource), typeof(TTarget)));
}

//return the default TypeMapper
return new TypeMapper<TSource, TTarget>();
}

public static void AddMapper<TS, TT>(ITypeMapper<TS, TT> o)
{
Mappers.Add(typeof(ITypeMapper<TS, TT>), o);
}

public static void ClearMappers()
{
Mappers.Clear();
}
}

public interface ITypeMapper<TSource, TTarget>
{
TTarget Map(TSource source, TTarget target);
}

public class TypeMapper<TSource, TTarget> : ITypeMapper<TSource, TTarget>
{
public virtual TTarget Map(TSource source, TTarget target)
{
target.InjectFrom(source);
target.InjectFrom<NullablesToNormal>(source);
target.InjectFrom<NormalToNullables>(source);
target.InjectFrom<IntToEnum>(source);
target.InjectFrom<EnumToInt>(source);
target.InjectFrom<MapperInjection>(source);

return target;
}
}

public class EnumerableTypeMapper<TSource, TTarget> : ITypeMapper<TSource, TTarget>
where TSource : class
where TTarget : class
{
public TTarget Map(TSource source, TTarget target)
{
if (source == null) return null;
var targetArgumentType = typeof(TTarget).GetGenericArguments()[0];

var list = Activator.CreateInstance(typeof(List<>).MakeGenericType(targetArgumentType));
var add = list.GetType().GetMethod("Add");

foreach (var o in source as System.Collections.IEnumerable)
{
var t = Creator.Create(targetArgumentType);
add.Invoke(list, new[] { Mapper.Map(o, t, o.GetType(), targetArgumentType) });
}
return (TTarget)list;
}
}

public static class TypeExtensions
{
//returns true if type is IEnumerable<> or ICollection<>, IList<> ...
public static bool IsEnumerable(this Type type)
{
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition().GetInterfaces().Contains(typeof(System.Collections.IEnumerable)))
return true;
}
return false;
}
}

public static class Creator
{
public static object Create(Type type)
{
if (type.IsEnumerable())
{
return Activator.CreateInstance(typeof(List<>).MakeGenericType(type.GetGenericArguments()[0]));
}

if (type.IsInterface)
throw new Exception("don't know any implementation of this type: " + type.Name);

return Activator.CreateInstance(type);
}
}

public class MapperInjection : ConventionInjection
{
public const int MaxDepth = 20;
public static int _depth = 0;

protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name &&
!c.SourceProp.Type.IsValueType && c.SourceProp.Type != typeof(string) &&
!c.SourceProp.Type.IsGenericType && !c.TargetProp.Type.IsGenericType
||
c.SourceProp.Type.IsEnumerable() &&
c.TargetProp.Type.IsEnumerable();
}

protected override object SetValue(ConventionInfo c)
{
if (c.SourceProp.Value == null)
{
return null;
}
if (_depth > MaxDepth)
return Mapper.MapFinal(c.SourceProp.Value, c.TargetProp.Value, c.SourceProp.Type, c.TargetProp.Type);
_depth++;
object val = Mapper.Map(c.SourceProp.Value, c.TargetProp.Value, c.SourceProp.Type, c.TargetProp.Type);
_depth--;
return val;
}
}

public class EnumToInt : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name &&
c.SourceProp.Type.IsSubclassOf(typeof(Enum)) && c.TargetProp.Type == typeof(int);
}
}

public class IntToEnum : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name &&
c.SourceProp.Type == typeof(int) && c.TargetProp.Type.IsSubclassOf(typeof(Enum));
}
}

//e.g. int? -> int
public class NullablesToNormal : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name &&
Nullable.GetUnderlyingType(c.SourceProp.Type) == c.TargetProp.Type;
}
}

//e.g. int -> int?
public class NormalToNullables : ConventionInjection
{


protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name &&
c.SourceProp.Type == Nullable.GetUnderlyingType(c.TargetProp.Type);
}
}

关于c# - ValueInjector Stack Overflow 映射实体与父实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13635043/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com