Игнорировать сопоставление одного свойства с Automapper


285

Я использую Automapper, и у меня есть следующий сценарий: Класс OrderModel имеет свойство с именем «ProductName», которого нет в базе данных. Поэтому, когда я пытаюсь сделать сопоставление с:

Mapper.CreateMap<OrderModel, Orders>(); 

Это генерирует исключение:

«Следующие 1 свойства в Project.ViewModels.OrderModel не сопоставлены:« ProductName »

Я прочитал в Wiki для проекций AutoMapper противоположный случай (дополнительный атрибут находится в месте назначения, а не в источнике, который фактически является моим случаем)

Как я могу избежать Autopper, чтобы сделать отображение этого свойства?


7
Automapper не работает таким образом. Это касается только свойств объекта назначения. Src может содержать 100 дополнительных свойств - Automapper отображает только свойства dest. Должно быть что-то еще, вызывающее исключение отображения. Можете ли вы опубликовать код, который не работает?
— PatrickSteele

Он делает то, что вы спрашиваете автоматически. Опубликовать код, чтобы уточнить
— BeRecursive

Посмотрите на следующие сообщения, они могут помочь вам stackoverflow.com/questions/4456519/… stackoverflow.com/questions/4052579/…
— Divi

3
@Patrick AutoMapper делает некоторые трюки с анализом имен методов / свойств. Возможно, что в источнике есть свойство, которое непреднамеренно отображается, даже если в месте назначения нет точного соответствия. Вот почему существует ForSourceMember (... Ignore ()), чтобы предотвратить это, когда это происходит.
— AaronLS

Ответы:


478

От Джимми Богарда: CreateMap<Foo, Bar>().ForMember(x => x.Blarg, opt => opt.Ignore());

Это в одном из комментариев в его блоге .


13
Кроме того, CreateMap<Foo, Bar>().ForSourceMember(x => x.Blarg, opt => opt.Ignore());может быть полезно
— stackoverfloweth

5
@stackoverfloweth ли вы не имели в виду: CreateMap<SourceType, DestType> (MemberList.Source).ForSourceMember(x => x.MySourceProperty, opt => opt.DoNotValidate())?
— Монти

13
Игнорировать было заменено на DoNotValidate в ForSourceMember: github.com/AutoMapper/AutoMapper/blob/master/docs/…
— Джейми

@Jamie @monty - я начал обновлять этот re: ваш комментарий, но похоже, что изменение синтаксиса влияет только на случай проекции (где свойство источника нужно игнорировать). Запрос OP состоит в том, чтобы игнорировать свойство назначения, поэтому Ignore()остается правильный синтаксис. Это потому, что изменение синтаксиса для Ignoreбыло сделано на ISourceMemberConfigurationExpressionинтерфейсе, но не на непересекающемся IMemberConfigurationExpression`3интерфейсе.
— умный пещерный человек

2
@Franva ForMember () на самом деле "ForDestinationMember ()"
— rvnlord

243

Я, возможно, немного перфекционист; Мне не очень нравится синтаксис ForMember (..., x => x.Ignore ()). Это мелочь, но это важно для меня. Я написал этот метод расширения, чтобы сделать его немного лучше:

public static IMappingExpression<TSource, TDestination> Ignore<TSource, TDestination>(
    this IMappingExpression<TSource, TDestination> map,
    Expression<Func<TDestination, object>> selector)
{
    map.ForMember(selector, config => config.Ignore());
    return map;
}

Это можно использовать так:

Mapper.CreateMap<JsonRecord, DatabaseRecord>()
        .Ignore(record => record.Field)
        .Ignore(record => record.AnotherField)
        .Ignore(record => record.Etc);

Вы также можете переписать его для работы params, но мне не нравится внешний вид метода с множеством лямбд.


6
Я знаю, что это выходит за рамки первоначального вопроса, но мне действительно нравится этот ответ, он чистый, очень легкий для чтения и мгновенного понимания плюс прост в повторном использовании
— Lski

Относительно params: Вы можете вернуть массив селекторов из одной лямбды, а затем отобразить каждый селектор с foreachили, Select()возможно, не менее грязно.
— jpaugh

спасибо @Steve Rukuts, для тех, кто ищет метод расширения, чтобы игнорировать исходные элементы, вы можете использовать это общедоступное статическое IMappingExpression <TSource, TDestination> IgnoreSourceValidation <TSource, TDestination> (это IMappingExpression <TSource, TDestination> карта, выражение <Func <TSource , объект >> селектор) {map.ForSourceMember (селектор, config => config.DoNotValidate ()); карта возврата; }
— Джейсон Диас

79

Ты можешь сделать это:

conf.CreateMap<SourceType, DestinationType>()
   .ForSourceMember(x => x.SourceProperty, y => y.Ignore());

Есть ли у Autopper расширение ForSourceMember?
— Погашено1

Я делаю это в настоящее время, но было бы идеально, чтобы НЕ создавать все эти игнорировать ...: /
— Том Stickel

Знаете ли вы, есть ли способ игнорировать, когда на самом деле делаете отображение, а не при создании карты?
— Сэм, я говорю, восстанови Монику

К вашему сведению: объединено со stackoverflow.com/questions/4052579/…
— Shog9

3
Для сценария, приведенного в вопросе, это должен быть принятый ответ. Текущий принятый ответ игнорирует сопоставление свойств в целевом объекте. Этот вопрос задает вопрос об игнорировании отображений в исходном объекте.
— Роб С.

28

Просто для тех, кто пытается сделать это автоматически, вы можете использовать этот метод расширения, чтобы игнорировать несуществующие свойства в типе назначения:

public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    var sourceType = typeof(TSource);
    var destinationType = typeof(TDestination);
    var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType)
        && x.DestinationType.Equals(destinationType));
    foreach (var property in existingMaps.GetUnmappedPropertyNames())
    {
        expression.ForMember(property, opt => opt.Ignore());
    }
    return expression;
}

использоваться следующим образом:

Mapper.CreateMap<SourceType, DestinationType>().IgnoreAllNonExisting();

спасибо Can Gencer за отзыв :)

источник: http://cangencer.wordpress.com/2011/06/08/auto-ignore-non-existing-properties-with-automapper/


3
К вашему сведению: объединено со stackoverflow.com/questions/4052579/…
— Shog9

1
Это не работает при введении IMapper. Mapper.GetAllTypeMaps не существует в последней версии AutoMapper. Кроме того, когда я настраиваю свои карты в AutoMapper.Profile, а затем внедряю IMapper, я получаю это исключение «Mapper not initialized. Call Initialize с соответствующей конфигурацией. Если вы пытаетесь использовать экземпляры mapper через контейнер или иным образом, убедитесь, что вы не вызывайте статические методы Mapper.Map, и если вы используете методы расширения ProjectTo или UseAsDataSource, убедитесь, что вы передаете соответствующий экземпляр IConfigurationProvider. "
— Ristogod

Я просто получаю 'Mapper' does not contain a definition for 'GetAllTypeMaps' [DSSTools]..
— Басси

2
@Bassie Использовать Mapper.Configuration.GetAllTypeMaps() источник
— Майк Бовенландер

28

Теперь есть (AutoMapper 2.0) IgnoreMapатрибут, который я собираюсь использовать, а не беглый синтаксис, который немного тяжелый ИМХО.


35
Атрибут ignore пропускает auto-mapper через ваше приложение.
— Филл

11
AutoMapper это одна вещь, которую я не против утечки повсюду. ;)
— Павел Краковяк

4
Вы всегда можете подумать о выводе IgnoreMapAttribute.
— Alapago

1
Это хороший способ игнорировать базовое свойство, которое наследуется во многих объектах. Избавляет от необходимости игнорировать его в каждой конфигурации сопоставления.
— Чейз Флорелл

23

При отображении модели представления обратно в модель домена, может быть намного проще просто проверить исходный список членов, а не целевой список членов.

Mapper.CreateMap<OrderModel, Orders>(MemberList.Source); 

Теперь моя проверка соответствия не завершается неудачей, требуя другого Ignore(), каждый раз, когда я добавляю свойство в свой класс домена.


7
Это то, что я искал, так полезно, когда нужно изменить только подмножество свойств объекта домена из гораздо более простого DTO.
— Адам Толи

5
Это ответ, дети, сделайте это официальным, чтобы новички не были сбиты с толку
— Петр М

0

Может использовать IgnoreAttribute для свойства, которое необходимо игнорировать


2
Его [IgnoreMap]отIgnoreMapAttribute
— fiorebat

-5

Привет всем, пожалуйста, используйте это, он работает нормально ... для автоматического сопоставления использовать несколько .ForMember в C #

        if (promotionCode.Any())
        {
            Mapper.Reset();
            Mapper.CreateMap<PromotionCode, PromotionCodeEntity>().ForMember(d => d.serverTime, o => o.MapFrom(s => s.promotionCodeId == null ? "date" : String.Format("{0:dd/MM/yyyy h:mm:ss tt}", DateTime.UtcNow.AddHours(7.0))))
                .ForMember(d => d.day, p => p.MapFrom(s => s.code != "" ? LeftTime(Convert.ToInt32(s.quantity), Convert.ToString(s.expiryDate), Convert.ToString(DateTime.UtcNow.AddHours(7.0))) : "Day"))
                .ForMember(d => d.subCategoryname, o => o.MapFrom(s => s.subCategoryId == 0 ? "" : Convert.ToString(subCategory.Where(z => z.subCategoryId.Equals(s.subCategoryId)).FirstOrDefault().subCategoryName)))
                .ForMember(d => d.optionalCategoryName, o => o.MapFrom(s => s.optCategoryId == 0 ? "" : Convert.ToString(optionalCategory.Where(z => z.optCategoryId.Equals(s.optCategoryId)).FirstOrDefault().optCategoryName)))
                .ForMember(d => d.logoImg, o => o.MapFrom(s => s.vendorId == 0 ? "" : Convert.ToString(vendorImg.Where(z => z.vendorId.Equals(s.vendorId)).FirstOrDefault().logoImg)))
                .ForMember(d => d.expiryDate, o => o.MapFrom(s => s.expiryDate == null ? "" : String.Format("{0:dd/MM/yyyy h:mm:ss tt}", s.expiryDate))); 
            var userPromotionModel = Mapper.Map<List<PromotionCode>, List<PromotionCodeEntity>>(promotionCode);
            return userPromotionModel;
        }
        return null;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.