ละเว้นการทำแผนที่หนึ่งคุณสมบัติด้วย Automapper


285

ฉันใช้ Automapper และฉันมีสถานการณ์ต่อไปนี้: Class OrderModel มีคุณสมบัติชื่อ 'ProductName' ที่ไม่ได้อยู่ในฐานข้อมูล ดังนั้นเมื่อฉันพยายามทำแผนที่ด้วย:

Mapper.CreateMap<OrderModel, Orders>(); 

มันสร้างข้อยกเว้น:

"คุณสมบัติ 1 รายการต่อไปนี้บน Project.ViewModels.OrderModel ไม่ได้ถูกแมป: 'ProductName'

ฉันได้อ่านที่วิกิพีเดียของ AutoMapper's for Projectionsในกรณีตรงกันข้าม (แอตทริบิวต์พิเศษอยู่ที่ปลายทางไม่ใช่ในแหล่งที่มาซึ่งเป็นกรณีของฉันจริง ๆ )

ฉันจะหลีกเลี่ยง automapper เพื่อทำการแมปคุณสมบัตินี้ได้อย่างไร


7
Automapper ไม่ทำงานอย่างนั้น มันเกี่ยวข้องกับคุณสมบัติบนวัตถุปลายทางเท่านั้น src สามารถมี 100 คุณสมบัติพิเศษ - Automapper จะจับคู่คุณสมบัติของปลายทางเท่านั้น ต้องมีสิ่งอื่นที่ทำให้เกิดข้อยกเว้นการแมป คุณช่วยโพสต์โค้ดว่าอะไรไม่ทำงานบ้าง?
PatrickSteele

มันทำในสิ่งที่คุณถามโดยอัตโนมัติ โพสต์รหัสเพื่อชี้แจง
BeRecursive

ลองดูที่โพสต์ต่อไปนี้สิ่งเหล่านี้อาจช่วยให้คุณstackoverflow.com/questions/4456519/… stackoverflow.com/questions/4052579//
Divi

3
@Patrick AutoMapper ใช้เทคนิคบางอย่างในการวิเคราะห์ชื่อ / คุณสมบัติ มีความเป็นไปได้ที่จะมีสถานที่ให้บริการในแหล่งที่มาที่ถูกแมปโดยไม่ได้ตั้งใจแม้ว่าจะไม่มีการจับคู่ที่แน่นอนในปลายทาง นี่คือเหตุผลที่มี ForSourceMember (... ละเว้น ()) เพื่อป้องกันสิ่งนี้เมื่อมันเกิดขึ้น
AaronLS

คำตอบ:


478

จาก Jimmy Bogard: 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())?
monty

12
Ignore ถูกแทนที่ด้วย DoNotValidate ใน ForSourceMember: github.com/AutoMapper/AutoMapper/blob/master/docs/…
Jamie

@Jamie @monty - ฉันเริ่มอัปเดตข้อความนี้ใหม่: ความคิดเห็นของคุณ แต่ดูเหมือนว่าการเปลี่ยนแปลงทางไวยากรณ์จะมีผลเฉพาะกับกรณีการฉายภาพ (ซึ่งคุณสมบัติแหล่งที่มาจะต้องถูกละเว้น) คำขอของ OP คือละเว้นคุณสมบัติปลายทางดังนั้น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> (IMource Expression นี้ <TSource, TDestination) วัตถุ >> ตัวเลือก) {map.ForSourceMember (ตัวเลือก config => config.DoNotValidate ()); แผนที่ส่งคืน; }
Jason Dias

79

คุณสามารถทำได้:

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

automapper มีส่วนขยาย ForSourceMember หรือไม่
แลก 1

ฉันทำสิ่งนี้ในขณะนี้ แต่จะเหมาะอย่างยิ่งที่จะไม่ต้องสร้างสิ่งที่ไม่สนใจเหล่านี้ ... : /
Tom Stickel

คุณรู้หรือไม่ว่ามีวิธีที่จะเพิกเฉยเมื่อทำแผนที่จริง ๆ และไม่เมื่อสร้างแผนที่?
Sam ฉันว่า Reinstate Monica

FYI: ผสานจากstackoverflow.com/questions/4052579/…
Shog9

3
สำหรับสถานการณ์ที่ให้ไว้ในคำถามนี้ควรเป็นคำตอบที่ยอมรับได้ คำตอบที่ยอมรับในปัจจุบันไม่สนใจการจับคู่ของคุณสมบัติในวัตถุปลายทาง คำถามนี้ถามเกี่ยวกับการละเว้นการแมปในวัตถุต้นฉบับ
Rob S.

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
FYI: ผสานจากstackoverflow.com/questions/4052579/…
Shog9

1
สิ่งนี้ไม่ทำงานเมื่อฉีด IMapper Mapper.GetAllTypeMaps ไม่มีอยู่ใน AutoMapper เวอร์ชันล่าสุด นอกจากนี้เมื่อฉันตั้งค่าแผนที่ของฉันใน AutoMapper.Profile จากนั้นจึงฉีด IMapper ฉันได้รับข้อยกเว้นนี้ "Mapper ไม่เริ่มต้นใช้งานเริ่มต้นการโทรด้วยการกำหนดค่าที่เหมาะสมหากคุณพยายามใช้อินสแตนซ์ mapper ผ่านคอนเทนเนอร์หรืออื่น ๆ ไม่มีการเรียกไปยังเมธอด Mapper.Map แบบสแตติกและถ้าคุณใช้วิธีการขยาย ProjectTo หรือ UseAsDataSource ตรวจสอบให้แน่ใจว่าคุณผ่านในอินสแตนซ์ IConfigurationProvider ที่เหมาะสม "
Ristogod

ฉันเพิ่งได้รับ'Mapper' does not contain a definition for 'GetAllTypeMaps' [DSSTools]..
Bassie

2
@Bassie ใช้Mapper.Configuration.GetAllTypeMaps() แหล่งข้อมูล
Mike Bovenlander

28

ตอนนี้มีIgnoreMapแอตทริบิวต์(AutoMapper 2.0) ซึ่งฉันจะใช้มากกว่าไวยากรณ์ที่คล่องแคล่วซึ่งเป็น IMHO ที่หนักหน่วงเล็กน้อย


35
คุณสมบัติการละเว้นการรั่วไหลของ mapper อัตโนมัติผ่านใบสมัครของคุณ
Phill

11
AutoMapper เป็นสิ่งหนึ่งที่ฉันไม่รังเกียจที่จะรั่วไหลไปทั่วสถานที่ ;)
Pawel Krakowiak

4
IgnoreMapAttributeคุณสามารถพิจารณาสืบมา
Alapago

1
นี่เป็นวิธีที่ดีในการเพิกเฉยคุณสมบัติฐานที่สืบทอดมาจากหลาย ๆ วัตถุ บันทึกจากไม่ต้องสนใจมันในทุกการกำหนดค่าการแมป
Chase Florell

23

เมื่อทำการแมปมุมมองแบบจำลองกลับไปยังแบบจำลองของโดเมนคุณสามารถตรวจสอบรายชื่อสมาชิกของแหล่งที่มาได้อย่างง่ายดายแทนที่จะเป็นรายชื่อสมาชิกปลายทาง

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

ตอนนี้การตรวจสอบการแมปของฉันไม่ได้ล้มเหลวโดยต้องมีอีกIgnore()ทุกครั้งที่ฉันเพิ่มคุณสมบัติให้กับคลาสโดเมน


7
นี่คือสิ่งที่ฉันกำลังมองหาดังนั้นมีประโยชน์เมื่อแก้ไขชุดย่อยของคุณสมบัติวัตถุโดเมนจาก DTO ที่ง่ายกว่ามาก
Adam Tolley

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;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.