Ігноруйте відображення однієї власності за допомогою Automapper


285

Я використовую Automapper, і у мене є такий сценарій: Клас OrderModel має властивість під назвою "ProductName", яка відсутня в базі даних. Тому коли я намагаюся зробити картографування за допомогою:

Mapper.CreateMap<OrderModel, Orders>(); 

Він створює виняток:

"Наступні 1 властивості Project.ViewModels.OrderModel не відображаються:" ProductName "

Я читав в WikiMe для проектування AutoMapper навпаки (додатковий атрибут знаходиться в пункті призначення, а не в джерелі, яке насправді є моїм випадком)

Як я можу уникнути автоматичного створення карти цього майна?


7
Automapper не працює таким чином. Його стосується лише властивостей об'єкта призначення. Src може містити 100 додаткових властивостей - Automapper відображає лише властивості dest. Має бути щось інше, що спричиняє виняток із картографування. Чи можете ви опублікувати якийсь код того, що не працює?
— PatrickSteele

Це робить те, що ви запитаєте автоматично. Опублікуйте код, щоб уточнити
— BeRecursive

Зверніть увагу на наступні посади, вони можуть допомогти вам stackoverflow.com/questions/4456519 / ... stackoverflow.com/questions/4052579 / ...
— Дива

3
@Patrick AutoMapper робить деякі хитрощі з аналізом методів / імен властивостей. Можливо, у джерелі є властивість, яке ненавмисно відображається, навіть якщо в пункті призначення немає точної відповідності. Ось чому існує ForSourceMember (... Ігнорувати ()), щоб запобігти цьому, коли це відбувається.
— 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()):?
— монт

12
Ігнорування замінено DoNotValidate у ForSourceMember: github.com/AutoMapper/AutoMapper/blob/master/docs/…
— Джеймі

@Jamie @monty - я почав оновлювати цей результат: ваш коментар, але схоже, що зміна синтаксису впливає лише на випадок проекції (де властивість джерела потрібно ігнорувати). Запит ОП полягає в ігноруванні властивості призначення, тому Ignore()залишається правильним синтаксисом. Це відбувається тому, що зміна синтаксису для Ignoreбуло внесено в ISourceMemberConfigurationExpressionінтерфейс, а не на роз'єднаний IMemberConfigurationExpression`3інтерфейс.
— smartcaveman

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> карта, Expression <Func <TSource , об’єкт >> селектор) {map.ForSourceMember (селектор, config => config.DoNotValidate ()); повернути карту; }
— Джейсон Діас

79

Ви можете зробити це:

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

Чи має розширення ForSourceMember у Autompper?
— Викуплено1

Я роблю це наразі, але було б ідеально НЕ треба створювати всі ці Ігнорувати ...: /
— Том Стікель

чи знаєте ви, чи є спосіб ігнорувати, коли насправді робите карти, а не створюєте карту?
— Сем, я кажу: Відновіть Моніку


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/



1
Це не працює, якщо вводити IMapper. Mapper.GetAllTypeMaps не існує в останній версії AutoMapper. Крім того, коли я встановлював свої карти в AutoMapper.Profile, а потім вводив IMapper, я отримав цей виняток "Mapper не ініціалізований. Виклик ініціалізувати з відповідною конфігурацією. Якщо ви намагаєтесь використовувати екземпляри mapper через контейнер чи іншим способом, переконайтеся, що ви не маєте жодних дзвінків до статичних методів Mapper.Map, і якщо ви використовуєте методи розширення ProjectTo або UseAsDataSource, переконайтеся, що ви переходите у відповідний екземпляр IConfigurationProvider. "
— Рістогод

Я щойно отримаю 'Mapper' does not contain a definition for 'GetAllTypeMaps' [DSSTools]..
— Бассі

2
@Bassie Використовуйте Mapper.Configuration.GetAllTypeMaps() джерело
— Майк Бовенлендер

28

Зараз є (AutoMapper 2.0) IgnoreMapатрибут, який я буду використовувати, а не вільний синтаксис, який є дещо важким IMHO.


35
Атрибут ігнорування, проте, пропускає автоматичне відображення через вашу програму.
— Філ

11
AutoMapper - це одна річ, яку я не проти просочуватися всюди. ;)
— Павло Краков'як

4
Ви завжди можете розглянути питання про похідне IgnoreMapAttribute.
— Алапаго

1
Це хороший спосіб ігнорувати базову властивість, яка успадковується по багатьох об'єктах. Позбавляє від необхідності ігнорувати його у кожному конфігурації відображення.
— Чейз Флорелл

23

Зіставляючи модель перегляду назад до доменної моделі, можна набагато чистіше просто перевірити список учасників, а не список членів призначення

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

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


7
Це те, що я шукав, настільки корисний, коли лише змінював підмножину властивостей об’єкта домену з набагато простішого DTO.
— Адам Толлі

5
Це відповідь, діти, зробіть це офіційним, щоб новачків не плутати
— Piotr M

0

Не вдалося використати IgnoreAttribute для властивості, яку потрібно ігнорувати


2
Її [IgnoreMap]зIgnoreMapAttribute
— fiorebat

-5

Привіт усім! Будь ласка, використовуйте це, це працює чудово ... для автоматичного картографування використовуйте кілька. Для члена 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.