Проблема сопоставления списка Emitmapper с коллекциями

StackOverflow https://stackoverflow.com/questions/5834574

Вопрос

Источник класса:

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; }
}

класс назначения

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; }
}

Я пытаюсь использовать Emitmapper, чтобы карту друг от друга; При сопоставлении от источника в десакция, вот пример кода:

[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());
    }

И я получил исключение,

Метод испытаний mblog.test.emitmappertest.shoulemapentitytomodel бросал исключение: system.exception: конструктор для типов [] не найден в System.collections.generic.ilist`1 [[mblog.core.models.post, mblog.core, версия = 1,0 .0.0, культура = нейтральная, publickeyToken = null]

Это было полезно?

Решение

У меня была та же проблема, но я нашел решение. Не списки пользователей для вашего объекта назначения. Если вы используете простые массивы в своем объекте mblog.core.models.post, вы должны получить красиво заполненный объект. Так что ваш класс назначения должен выглядеть так:

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; }
}

Другие советы

Этот ответ показывает, как справиться с Ienumerable с Ienumerable: Emitmapper и List

Я считаю, что это может быть применено к этому делу тоже. Взглянем:

Это может быть сделано создание пользовательского класса, внедряя интерфейс «iCustomConverterProvider» и добавление конвертека в «DefaultMapConfig».

Глядя на исходный код EmitMapper, я нашел класс с именем "ArraysConverterProvider", который является общим преобразователем по умолчанию от ICOLLECTIONS в массивы.

Адаптировать код из этого класса для работы с ienumerable коллекциями:

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;
        }
    }

Этот код представляет собой только копию с минимальной адаптацией, насколько это возможно, и может применяться к объектам со многими уровнями иерархии.

Вы можете использовать приведенный выше код со следующей командой:

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

Это сэкономило мой день, и я тоже надеюсь сэкономить ваш! хе -хе

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top