Игнорировать сопоставление одного свойства с 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.