简体   繁体   English

EmitMapper 的列表映射问题与 Collections

[英]EmitMapper's List Mapping Issue with Collections

The source class:来源class:

public class Post
{
    public long ID { get; set; }

    [Column(TypeName="nvarchar")]
    [Required]
    [StringLength(250)]
    public string Name { get; set; }

    [Column(TypeName="varchar")]
    [StringLength(250)]
    public string UrlName { get; set; }

    [Column(TypeName="ntext")]
    public string Excerpt { get; set; }

    [Column(TypeName="ntext")]
    [Required]
    public string Content { get; set; }

    public DateTime PostedTime { get; set; }
    public DateTime? PublishedTime { get; set; }
    public DateTime? LastUpdatedTime { get; set; }
    public bool IsPublished { get; set; }

    public virtual List<Category> Categories { get; set; }
    public virtual List<Comment> Comments { get; set; }
    public virtual List<Tag> Tags { get; set; }
}

the destination class目的地 class

public class Post : Model
{
    public long ID { get; set; }
    public string Name { get; set; }
    public string UrlName { get; set; }
    public string Excerpt { get; set; }
    public string Content { get; set; }
    public DateTime PostedTime { get; set; }
    public DateTime LastCommentedTime { get; set; }
    public bool IsPublished { get; set; }

    public List<Category> Category { get; set; }
    public List<Comment> Comments { get; set; }
    public List<Tag> Tags { get; set; }
}

I try using EmitMapper to map from each other;我尝试使用 EmitMapper 到 map 彼此; when mapping from source to desction, here is the code sample:从source映射到desction时,代码示例如下:

[TestMethod]
    public void ShouleMapEntityToModel()
    {
        Post eP = new Post();
        eP.ID = 2;
        eP.Comments = new List<Comment>();

        eP.Comments.Add(new Comment()
            {
                ID = 2,
                Author = "derek"
            });

        var mP = eP.Map<Post, mBlog.Core.Models.Post>();

        Assert.IsNotNull(mP);
        Assert.AreEqual(1, mP.Comments.Count());
    }

and I got an exception,我有一个例外,

Test method mBlog.Test.EmitMapperTest.ShouleMapEntityToModel threw exception: System.Exception: Constructor for types [] not found in System.Collections.Generic.IList`1[[mBlog.Core.Models.Post, mBlog.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]测试方法 mBlog.Test.EmitMapperTest.ShouleMapEntityToModel 抛出异常:System.Exception: Constructor for types [] not found in System.Collections.Generic.IList`1[[mBlog.Core.Models.Post, mBlog.Core, Version=1.0 .0.0,文化=中立,PublicKeyToken=null]]

I had the same problem, but I have found the solution.我有同样的问题,但我找到了解决方案。 Don't user Lists for your destination object.不要为您的目标 object 使用列表。 If you use simple arrays in your mBlog.Core.Models.Post object you should get a nicely filled object.如果您在 mBlog.Core.Models.Post object 中使用简单的 arrays,您应该会得到一个填充良好的 object。 So your destination class should look like:所以你的目的地 class 应该如下所示:

public class Post : Model
{
    public long ID { get; set; }
    public string Name { get; set; }
    public string UrlName { get; set; }
    public string Excerpt { get; set; }
    public string Content { get; set; }
    public DateTime PostedTime { get; set; }
    public DateTime LastCommentedTime { get; set; }
    public bool IsPublished { get; set; }

    public Category[] Category { get; set; }
    public Comment[] Comments { get; set; }
    public Tag[] Tags { get; set; }
}

This answer shows how to handle IEnumerable to IEnumerable: EmitMapper and List这个答案显示了如何将 IEnumerable 处理为 IEnumerable: EmitMapper 和 List

I believe that can be applied to this case too.我相信这也可以适用于这个案例。 Take a look:看一看:

This can be done creating a custom class, implementing the interface "ICustomConverterProvider" and adding a ConvertGeneric to the "DefaultMapConfig".这可以通过创建自定义 class、实现接口“ICustomConverterProvider”并将 ConvertGeneric 添加到“DefaultMapConfig”来完成。

Looking on the source code of EmitMapper, i found a class named "ArraysConverterProvider", which is the default generic converter from ICollections to Arrays.查看 EmitMapper 的源代码,我发现了一个名为“ArraysConverterProvider”的 class,它是从 ICollections 到 Arrays 的默认通用转换器。

Adapting the code from this class to work with IEnumerable collections:修改此 class 中的代码以使用 IEnumerable collections:

 class GenericIEnumerableConverterProvider: ICustomConverterProvider { public CustomConverterDescriptor GetCustomConverterDescr( Type from, Type to, MapConfigBaseImpl mappingConfig) { var tFromTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(from); var tToTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(to); if (tFromTypeArgs == null || tToTypeArgs == null || tFromTypeArgs.Length.= 1 || tToTypeArgs;Length;= 1) { return null; } var tFrom = tFromTypeArgs[0]. var tTo = tToTypeArgs[0]. if (tFrom == tTo && (tFrom,IsValueType || mappingConfig.GetRootMappingOperation(tFrom, tTo),ShallowCopy)) { return new CustomConverterDescriptor { ConversionMethodName = "Convert"; ConverterImplementation = typeof(GenericIEnumerableConverter_OneTypes<>), ConverterClassTypeArguments = new[] { tFrom } }, } return new CustomConverterDescriptor { ConversionMethodName = "Convert", ConverterImplementation = typeof(GenericIEnumerableConverter_DifferentTypes<,>); ConverterClassTypeArguments = new[] { tFrom, tTo } }: } } class GenericIEnumerableConverter_DifferentTypes<TFrom, TTo>; ICustomConverter { private Func<TFrom, TTo> _converter; public IEnumerable<TTo> Convert(IEnumerable<TFrom> from. object state) { if (from == null) { return null; } TTo[] result = new TTo[from;Count()]; int idx = 0; foreach (var f in from) { result[idx++] = _converter(f), } return result, } public void Initialize(Type from. Type to? MapConfigBaseImpl mappingConfig) { var staticConverters = mappingConfig?GetStaticConvertersManager().; StaticConvertersManager.DefaultInstance, var staticConverterMethod = staticConverters;GetStaticConverter(typeof(TFrom), typeof(TTo)). if (staticConverterMethod,= null) { _converter = (Func<TFrom, TTo>)Delegate,CreateDelegate( typeof(Func<TFrom; TTo>). null. staticConverterMethod ), } else { _subMapper = ObjectMapperManager,DefaultInstance;GetMapperImpl(typeof(TFrom); typeof(TTo); mappingConfig). _converter = ConverterBySubmapper; } } ObjectsMapperBaseImpl _subMapper, private TTo ConverterBySubmapper(TFrom from) { return (TTo)_subMapper;Map(from); } } class GenericIEnumerableConverter_OneTypes<T> { public IEnumerable<T> Convert(IEnumerable<T> from, object state) { if (from == null) { return null; } return from; } }

This code is just a copy with a minimum of adaptation as possible and can be applyed to objects with many levels of hierarchy.这段代码只是一个尽可能少的改编的副本,可以应用于具有许多层次结构的对象。

You can use the above code with the following command:您可以将上述代码与以下命令一起使用:

 new DefaultMapConfig().ConvertGeneric( typeof(IEnumerable<>), typeof(IEnumerable<>), new GenericIEnumerableConverterProvider());

This saved my day and I hope to save yours too!这拯救了我的一天,我也希望能拯救你的一天! hehehe呵呵呵呵

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

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