2011-07-04 17 views
15

मैं नीचे दिए गए उदाहरण में दिखाए गए अनुसार डीटीओ में डोमेन ऑब्जेक्ट्स को फ़्लैट कर रहा हूं:नेस्टेड ऑब्जेक्ट्स को फ़्लैट करने के लिए ऑटोमैपर का उपयोग करने का एक बेहतर तरीका?

public class Root 
{ 
    public string AParentProperty { get; set; } 
    public Nested TheNestedClass { get; set; } 
} 

public class Nested 
{ 
    public string ANestedProperty { get; set; } 
} 

public class Flattened 
{ 
    public string AParentProperty { get; set; } 
    public string ANestedProperty { get; set; } 
} 

// I put the equivalent of the following in a profile, configured at application start 
// as suggested by others: 

Mapper.CreateMap<Root, Flattened>() 
     .ForMember 
     (
      dest => dest.ANestedProperty 
      , opt => opt.MapFrom(src => src.TheNestedClass.ANestedProperty) 
     ); 

// This is in my controller: 
Flattened myFlattened = Mapper.Map<Root, Flattened>(myRoot); 

मैंने कई उदाहरण देखे हैं, और अब तक यह एक नेस्टेड पदानुक्रम को फ़्लैट करने का तरीका प्रतीत होता है। यदि बच्चे के ऑब्जेक्ट में कई गुण हैं, हालांकि, यह दृष्टिकोण अधिक कोडिंग को सहेजता नहीं है।

मुझे यह उदाहरण मिला:

http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx

लेकिन मैप() फ़ंक्शन द्वारा आवश्यक मैप किए गए ऑब्जेक्ट्स के उदाहरणों की आवश्यकता है, जो प्रोफ़ाइल के साथ काम नहीं करेंगे जैसा कि मैं समझता हूं।

मैं ऑटोमैपर के लिए नया हूं, इसलिए मैं जानना चाहता हूं कि ऐसा करने का एक बेहतर तरीका है या नहीं।

+0

मुझे जॉन के समान चुनौती है। – noocyte

+0

कोई भी इस पर मदद नहीं कर सकता है? –

उत्तर

10

ऑटोमैपर के नवीनतम संस्करण में, एक नामकरण सम्मेलन है जिसका उपयोग आप एकाधिक .Member बयान से बचने के लिए कर सकते हैं।

अपने उदाहरण में, यदि आप ऐसा करने पर आपका चपटा वर्ग अद्यतन:

Mapper.CreateMap<Root, Flattened>(); 

Automapper होगा (प्रथा के अनुसार) मानचित्र Root.TheNestedClass.ANestedProperty रहे हैं:

public class Flattened 
{ 
    public string AParentProperty { get; set; } 
    public string TheNestedClassANestedProperty { get; set; } 
} 

आप ForMember बयान के उपयोग से बचने कर सकते हैं इस मामले में Flattened.TheNestedClassANestedProperty। जब आप असली कक्षा के नाम, ईमानदार का उपयोग कर रहे हैं तो यह कम बदसूरत लग रहा है!

+0

ऑटोमैपर के उपयोग के आधार पर मेरे दृश्य मॉडल गुणों का नामकरण करना कुछ ऐसा नहीं है जिसे मैं करना चाहता हूं। मैंने जवाब की सराहना की लेकिन समाधान के दुष्प्रभावों ने मुझे मूल प्रश्न में तकनीक का उपयोग किया होगा। – Choco

3

2 अधिक संभव समाधान:

Mapper.CreateMap<Nested, Flattened>() 
    .ForMember(s=>s.AParentProperty, o=>o.Ignore()); 
Mapper.CreateMap<Root, Flattened>() 
    .ForMember(d => d.ANestedProperty, o => o.MapFrom(s => s.TheNestedClass)); 

एक वैकल्पिक दृष्टिकोण नीचे हो सकता है, लेकिन यह Mapper.AssertConfigurationIsValid() पारित नहीं होता।

Mapper.CreateMap<Nested, Flattened>() 
//.ForMember map your properties here 
Mapper.CreateMap<Root, Flattened>() 
//.ForMember... map you properties here 
.AfterMap((s, d) => Mapper.Map(s.TheNestedClass, d)); 
+1

अच्छा दृष्टिकोण; बहुत बुरी कॉलिंग 'Mapper.AssertConfigurationIsValid();' इस कॉन्फ़िगरेशन पर दो त्रुटियों के साथ विफल रहता है (दो मानचित्र बनाए गए हैं, जिनमें से कोई भी गंतव्य प्रकार की गुणों को पूरी तरह से कवर नहीं करता है) –

+3

यह सुनिश्चित नहीं करता कि यह कितने फ़ील्ड हैं यदि समस्या हल करती है नेस्टेड कक्षा में? यदि ओपेड ऑब्जेक्ट से मैप करना चाहिए तो फ़्लैटेड ऑब्जेक्ट में कई गुण हैं, तो ओपी "गंतव्य सदस्य के लिए" कथन जोड़ना चाहता है। –

+0

यह सम्मेलन दृष्टिकोण नामकरण का एक विकल्प है। ऑटोमैपर के नामकरण सम्मेलनों के अनुरूप सभी समय तक संपत्ति नामों को बदलने/दोबारा बदलने की संभावना नहीं है। –

1

मैं विस्तार विधि लिखा समान समस्या को हल करने के लिए:

public static IMappingExpression<TSource, TDestination> FlattenNested<TSource, TNestedSource, TDestination>(
    this IMappingExpression<TSource, TDestination> expression, 
    Expression<Func<TSource, TNestedSource>> nestedSelector, 
    IMappingExpression<TNestedSource, TDestination> nestedMappingExpression) 
{ 
    var dstProperties = typeof(TDestination).GetProperties().Select(p => p.Name); 

    var flattenedMappings = nestedMappingExpression.TypeMap.GetPropertyMaps() 
                .Where(pm => pm.IsMapped() && !pm.IsIgnored()) 
                .ToDictionary(pm => pm.DestinationProperty.Name, 
                    pm => Expression.Lambda(
                     Expression.MakeMemberAccess(nestedSelector.Body, pm.SourceMember), 
                     nestedSelector.Parameters[0])); 

    foreach (var property in dstProperties) 
    { 
     if (!flattenedMappings.ContainsKey(property)) 
      continue; 

     expression.ForMember(property, opt => opt.MapFrom((dynamic)flattenedMappings[property])); 
    } 

    return expression; 
} 

तो अपने मामले में यह इस तरह इस्तेमाल किया जा सकता:

var nestedMap = Mapper.CreateMap<Nested, Flattened>() 
         .IgnoreAllNonExisting(); 

Mapper.CreateMap<Root, Flattened>() 
     .FlattenNested(s => s.TheNestedClass, nestedMap); 

IgnoreAllNonExisting()here से है।

हालांकि यह सार्वभौमिक समाधान नहीं है, लेकिन यह सरल मामलों के लिए पर्याप्त होना चाहिए।

तो,

  1. आप गंतव्य के गुण
  2. Mapper.AssertConfigurationIsValid() में सपाट का पालन करना पारित
  3. आप गैर स्थिर एपीआई में इस विधि का उपयोग कर सकते हैं (एक प्रोफाइल की जरूरत नहीं है) साथ ही
+1

मैं इसे ऑटोमैपर के नवीनतम संस्करण का उपयोग करके काम करने के लिए नहीं मिल सकता। MappingExpression.TypeMap अब उपलब्ध नहीं है। –

0

किसी अन्य उत्तर में सुधार करने के लिए, दोनों मैपिंग के लिए MemberList.Source निर्दिष्ट करें और नेस्टेड संपत्ति को अनदेखा करने के लिए सेट करें। प्रमाणीकरण तब ठीक हो जाता है।

Mapper.Initialize(cfg => 
{ 
    cfg.CreateMap<SrcNested, DestFlat>(MemberList.Source); 
    cfg.CreateMap<SrcRoot, DestFlat>(MemberList.Source) 
     .ForSourceMember(s => s.Nested, x => x.Ignore()) 
     .AfterMap((s, d) => Mapper.Map(s.Nested, d)); 
}); 

Mapper.AssertConfigurationIsValid(); 

var dest = Mapper.Map<SrcRoot, DestFlat>(src); 
संबंधित मुद्दे

 संबंधित मुद्दे