Ігноруйте відображення однієї власності за допомогою 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.