简体   繁体   English

EmitMapper-从抽象模型对象到抽象DTO的通用映射

[英]EmitMapper - Generic mapping from abstract model object to abstract DTO

I need some help transitioning from ValueInjecter to EmitMapper (I've decided so for performance reasons). 我需要一些帮助,从ValueInjecter过渡到EmitMapper (出于性能原因,我决定这样做)。 My use case is one of the most common ones: mapping a Model object to a DTO, based on some rules. 我的用例是最常见的用例之一:根据一些规则将Model对象映射到DTO。

One of this rules is: if a property's type is a subclass of DomainObject, then it should be mapped it to its correspondent DTO . 该规则之一是: 如果属性的类型是DomainObject的子类,则应将其映射到其对应的DTO With concrete types that's ok, but I also want it to work with abstract types. 可以使用具体类型,但是我也希望它可以与抽象类型一起使用。 The problem is that I don't how to tell EmitMapper which DTO should be used, in a dynamic fashion. 问题是我不怎么以动态的方式告诉EmitMapper应该使用哪个DTO。

In ValueInjecter code: 在ValueInjecter代码中:

public bool IsDomainObjectAndTargetIsDto(ConventionInfo it) 
{
    return it.SourceProp.Value.IsNotNull()
        && typeof(DomainObject).IsAssignableFrom(it.SourceProp.Type)
        && it.TargetProp.Type.Name.EndsWith("DTO");
}

As all of my DTOs implements DTO<> interface, I thought I could use EmitMapper's DefaultMapConfig.ConvertGeneric method but I just can't figure out how. 由于我所有的DTO都实现了DTO<>接口,所以我认为我可以使用EmitMapper的DefaultMapConfig.ConvertGeneric方法,但我不知道如何实现。

Just for completeness, I include my current (not working) code: 为了完整起见,我包括了我当前的代码(无效):

public class ModelToDtoConventions() 
{
    public IMappingConfigurator GetConfig() 
    {
        return new DefaultMapConfig()
            .ConvertUsing<IdentificableObject, int>(o => o.Id)
            .ConvertGeneric(
                typeof (DomainObject), 
                typeof (DTO<>),
                new DefaultCustomConverterProvider(
                    typeof (DomainObjectToDtoConverter<>)
                )
            );
    }
}

public class DomainObjectToDtoConverter<TDomainObject>
{
    public DTO<TDomainObject> Convert(TDomainObject from, object state)
    {
        return (DTO<TDomainObject>)this.CreateDtoFor(@from);
    }

    private object CreateDtoFor(object modelObject)
    {
        var modelType = modelObject.GetType();
        var dtoInterface = typeof(DTO<>).MakeGenericType(modelType);

        var dtoType = dtoInterface
            .GetConcreteSubtypes()
            .Single();

        return Activator.CreateInstance(dtoType);
    }
}

When I try to use this mapping on a test, I'm getting the following exception 当我尝试在测试中使用此映射时,出现以下异常

'MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model' failed: System.ArgumentException : Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
    at EmitMapper.MappingConfiguration.MapConfigBaseImpl.GetGenericConverter(Type from, Type to)
    at EmitMapper.MappingConfiguration.MapConfigBaseImpl.FilterOperations(Type from, Type to, IEnumerable`1 operations)
    at EmitMapper.MappingConfiguration.DefaultMapConfig.GetMappingOperations(Type from, Type to)
    at EmitMapper.EmitBuilders.MappingBuilder.BuildCopyImplMethod()
    at EmitMapper.ObjectMapperManager.BuildObjectsMapper(String MapperTypeName, Type from, Type to, IMappingConfigurator mappingConfigurator)
    at EmitMapper.ObjectMapperManager.GetMapperInt(Type from, Type to, IMappingConfigurator mappingConfigurator)
    at EmitMapper.ObjectMapperManager.GetMapperImpl(Type from, Type to, IMappingConfigurator mappingConfigurator)
    at MyProject.WebApi.Adapters.DTOInjector.Transform[TDestination](IMappingConfigurator config, Object source, TDestination destination) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 56
    at MyProject.WebApi.Adapters.DTOInjector.CreateDto[TDTO](Object entity) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 47
    at MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model() in c:\Users\faloi\Documents\GitHub\api\WebApi.Test\Utils\DTOInjectorTest.cs:line 334 c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs  56  

EDIT: this is an example of objects that I'd like to map. 编辑:这是我要映射的对象的示例。

//Domain objects
public class Game
{
    public IEnumerable<Map> Maps { get; set; }
    public Map MostPlayedMap { get; set; }

    public Game()
    {
        this.Maps = new List<Map>();
    }
}

public abstract class Map : DomainObject
{
    public string Name { get; set; }
}

public class BombDefuseMap : Map
{
    public Player BombHolder { get; set; }
}

public class HostageRescueMap : Map
{
    public int QuantityOfHostages { get; set; }
}

//DTOs
public class GameDTO : DTOWithId<Game>
{
    public List<MapDTO> Maps { get; set; }
    public MapDTO MostPlayedMap { get; set; }
}

public abstract class MapDTO
{
    public string Name { get; set; }
}

public class BombDefuseMapDTO : MapDTO, DTO<BombDefuseMap>
{
    public int BombHolder { get; set; }
}

public class HostageRescueMapDTO : MapDTO, DTO<HostageRescueMap>
{
    public int QuantityOfHostages { get; set; }
}

if you're concerned about performance have a look at this page: http://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection 如果您担心性能,请访问以下页面: http : //valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection

it's an injections that performs much better but you don't get the value in the matching algorithm, most times you don't need it anyway 这是一种性能要好得多的进样,但是您在匹配算法中无法获得所需的值,多数情况下您始终不需要它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM