我知道两个工具:Value injector和Automapper。他们每个人目前都支持我真正需要的功能之一。 :)背景:我正在使用存储过程从DB加载数据。关系1到多个作为XML属性处理。让我们考虑以下示例
public class AutorDto
{
public string Name { get; set; }
public List<Post> Posts { get; set; }
public ICity City { get; set; }
}
public interface ICity
{
string Name { get; set; }
string Code { get; set; }
}
public class CityDto
{
public string Name { get; set; }
public string Code { get; set; }
}
public class PostDto
{
public DateTime Date { get; set; }
public string Content { get; set; }
}
我有存储过程,它将在以下模式中返回此结构:
public class Autor_From_Stored_Procedure
{
public string Name { get; set; }
public string Posts { get; set; }
public string CityName { get; set; }
public string CityCode { get; set; }
}
为了将Autor_From_Stored_Procedure映射到AutorDto,我们必须处理两个主题:
从XML反序列化(我已设法使用automapper处理此问题。我已使用此主题:Automapper to create object from XML)和本文:http://www.codeproject.com/Articles/706992/Using-AutoMapper-with-Complex-XML-Data
Unflattening。看起来,AutoMapper不支持基于约定的unflattening。真的吗 ?我看到,有可能将一些字符串(例如“City”)声明为Unflattened对象并且一切都应该有效 - 但值注入器将此作为基于对话的标准提供: objectToIll.InjectFrom&lt; UnflatLoopInjection&gt;(对象) - 没有必要声明哪些属性[特定名称]会被声明为什么?这也适用于automapper吗?
如果没有,那么也许我应该专注于价值注入器。如果是这样 - 1)点的问题仍然有效(希望它像在automapper中一样容易解决)
佩妮为你的想法!
@@更新
我已经改变了Dto定义,将界面添加到City(因为这是我的情况)
答案 0 :(得分:1)
我会将问题发布到我的问题 - 也许它会帮助某人。我已经从Automapper搬到了Valueinjecter。使用自定义AddMap()和使用XmlSerializer(这里没有魔法)
完成Xml绑定但事实证明,“Autor”类上的接口会出现问题(和deflattening)你不能简单地创建接口实例,这就是问题所在。我已经修改了稍微有点值的Tunnelier类来处理这种情况。
首先,我试图用某种方式覆盖这个约定(如果你找到属性ISomething,剪切“我”添加“Dto”但它不是优雅的解决方案。所以我最终得到自定义:Inteface +类映射(所以我我指出:如果你看到ISomething接口,创建SomethingDto的实例)这是修改后的代码(也许这可以添加到valueinjecter实现?)主要的“Mapper”类不是部分所以我为那些定义了新类映射:
namespace Omu.ValueInjecter
{
public partial class MapperActivations
{
public static ConcurrentDictionary<Type, Type> InterfaceActivations = new ConcurrentDictionary<Type, Type>();
public static void AddInterfaceActivation<Interface, Class>()
{
InterfaceActivations.AddOrUpdate(typeof(Interface), typeof(Class), (key, oldValue) => typeof(Class));
}
}
}
以下是修改后的valueInjected类:
public static class TunnelierCustom
{
public static PropertyWithComponent Digg(IList<string> trail, object o)
{
var type = o.GetType();
if (trail.Count == 1)
{
return new PropertyWithComponent { Component = o, Property = type.GetProperty(trail[0]) };
}
var prop = type.GetProperty(trail[0]);
var val = prop.GetValue(o);
if (val == null)
{
if (prop.PropertyType.IsInterface)
{
if (MapperActivations.InterfaceActivations.ContainsKey(prop.PropertyType))
{
val = Activator.CreateInstance(MapperActivations.InterfaceActivations[prop.PropertyType]);
}
else
{
throw new Exception("Unable to create instance of: " + prop.PropertyType.Name + ". Are you missing InterfaceActivations bidning? Please add it using MapperActivations.AddInterfaceActivation<Interface, Class>() statement");
}
}
else
{
val = Activator.CreateInstance(prop.PropertyType);
}
prop.SetValue(o, val);
}
trail.RemoveAt(0);
return Digg(trail, val);
}
public static PropertyWithComponent GetValue(IList<string> trail, object o, int level = 0)
{
var type = o.GetType();
if (trail.Count == 1)
{
return new PropertyWithComponent { Component = o, Property = type.GetProperty(trail[0]), Level = level };
}
var prop = type.GetProperty(trail[0]);
var val = prop.GetValue(o);
if (val == null) return null;
trail.RemoveAt(0);
return GetValue(trail, val, level + 1);
}
}
/// <summary>
/// performs flattening and unflattening
/// first version of this class was made by Vadim Plamadeala ☺
/// </summary>
public static class UberFlatterCustom
{
public static IEnumerable<PropertyWithComponent> Unflat(string flatPropertyName, object target, Func<string, PropertyInfo, bool> match, StringComparison comparison)
{
var trails = TrailFinder.GetTrails(flatPropertyName, target.GetType().GetProps(), match, comparison, false).Where(o => o != null);
return trails.Select(trail => TunnelierCustom.Digg(trail, target));
}
public static IEnumerable<PropertyWithComponent> Unflat(string flatPropertyName, object target, Func<string, PropertyInfo, bool> match)
{
return Unflat(flatPropertyName, target, match, StringComparison.Ordinal);
}
public static IEnumerable<PropertyWithComponent> Unflat(string flatPropertyName, object target)
{
return Unflat(flatPropertyName, target, (upn, pi) => upn == pi.Name);
}
public static IEnumerable<PropertyWithComponent> Flat(string flatPropertyName, object source, Func<string, PropertyInfo, bool> match)
{
return Flat(flatPropertyName, source, match, StringComparison.Ordinal);
}
public static IEnumerable<PropertyWithComponent> Flat(string flatPropertyName, object source, Func<string, PropertyInfo, bool> match, StringComparison comparison)
{
var trails = TrailFinder.GetTrails(flatPropertyName, source.GetType().GetProps(), match, comparison).Where(o => o != null);
return trails.Select(trail => TunnelierCustom.GetValue(trail, source));
}
public static IEnumerable<PropertyWithComponent> Flat(string flatPropertyName, object source)
{
return Flat(flatPropertyName, source, (up, pi) => up == pi.Name);
}
}
public class UnflatLoopCustomInjection : ValueInjection
{
protected override void Inject(object source, object target)
{
var sourceProps = source.GetType().GetProps();
foreach (var sp in sourceProps)
{
Execute(sp, source, target);
}
}
protected virtual bool Match(string upn, PropertyInfo prop, PropertyInfo sourceProp)
{
return prop.PropertyType == sourceProp.PropertyType && upn == prop.Name;
}
protected virtual void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp)
{
tp.SetValue(target, sp.GetValue(source));
}
protected virtual void Execute(PropertyInfo sp, object source, object target)
{
if (sp.CanRead)
{
var endpoints = UberFlatterCustom.Unflat(sp.Name, target, (upn, prop) => Match(upn, prop, sp)).ToArray();
foreach (var endpoint in endpoints)
{
SetValue(source, endpoint.Component, sp, endpoint.Property);
}
}
}
}
这是示例用法:
MapperActivations.AddInterfaceActivation<ICity, City>();
Mapper.AddMap<Auto_From_Stored_Procedure, AutorDto>(src =>
{
var res = new User();
res.InjectFrom<UnflatLoopCustomInjection>(src);
res.Posts = Mapper.Map<XElement, List<Posts>>(src.PostsXml , "PostDto"); //this is mapping using XmlSerializer, PostsXml is XElement.Parse(Posts) in Autor_From_Stored_Procedure.
return res;
});
答案 1 :(得分:0)