mapping rto एक DTO को अनफ़्लैट करने के लिए AutoMapper का उपयोग करना




rto office up (6)

मैं अपने DTO से अपने डोमेन ऑब्जेक्ट्स पर जाने में कुछ समय बचाने के लिए AutoMapper का उपयोग करने की कोशिश कर रहा हूं, लेकिन मुझे मैप को कॉन्फ़िगर करने में परेशानी हो रही है ताकि यह काम करे, और मुझे आश्चर्य हो रहा है कि क्या AutoMapper गलत टूल हो सकता है काम।

डोमेन ऑब्जेक्ट (एक इकाई और एक मान) के इस उदाहरण पर विचार करें:

public class Person
{
    public string Name { get; set; }
    public StreetAddress Address { get; set; }
}

public class StreetAddress
{
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

मेरा DTO (एक Linq-to-SQL ऑब्जेक्ट से) इस तरह मोटे तौर पर देख रहा है:

public class PersonDTO
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

मैं अपनी रिपॉजिटरी में ऐसा करने में सक्षम होना चाहता हूं:

return Mapper.Map<PersonDTO, Person>(result);

मैंने ऑटोमैपर को हर तरह से कॉन्फ़िगर करने की कोशिश की है जो मैं समझ सकता हूं, लेकिन मुझे जेनेरिक मिसिंग टाइप मैप कॉन्फ़िगरेशन या असमर्थित मैपिंग त्रुटि मिलती रहती है, जिसमें कोई विवरण नहीं है कि मुझे यह बताएं कि मैं कहां असफल रहा हूं।

मैंने कई अलग-अलग विन्यासों की कोशिश की है, लेकिन यहाँ कुछ हैं:

Mapper.CreateMap<PersonDTO, Person>()
    .ForMember(dest => dest.Address, opt => opt.MapFrom(Mapper.Map<Person, Domain.StreetAddress>));

तथा

Mapper.CreateMap<Person, Domain.Person>()
    .ForMember(dest => dest.Address.Address1, opt => opt.MapFrom(src => src.Address))
    .ForMember(dest => dest.Address.City, opt => opt.MapFrom(src => src.City))
    .ForMember(dest => dest.Address.State, opt => opt.MapFrom(src => src.State));

मैंने पढ़ा है कि AutoMapper के साथ समतल वस्तुओं को आसान है, लेकिन उन्हें unflattening आसान नहीं है ... या संभव भी नहीं है। क्या कोई मुझे बता सकता है कि क्या मैं असंभव को करने की कोशिश कर रहा हूं, और अगर नहीं तो मैं क्या कर रहा हूं?

ध्यान दें कि मेरी वास्तविक वस्तुएं थोड़ी अधिक जटिल हैं, इसलिए यह संभव है कि मैं उस जानकारी को छोड़ रहा हूं जो त्रुटि की कुंजी है ... अगर मैं जो देख रहा हूं वह सही है तो मैं अधिक जानकारी प्रदान कर सकता हूं या परीक्षण के लिए अपनी वस्तुओं को सरल बनाना शुरू कर सकता हूं ।


टिप्पणी पोस्ट नहीं की जा सकती, इसलिए उत्तर पोस्ट करना। मुझे लगता है कि AutoMapper कार्यान्वयन में कुछ बदलाव थे इसलिए जवाब https://.com/a/5154321/2164198 हैनस द्वारा प्रस्तावित अब अनिवार्य नहीं है। हालांकि इस तरह के परिदृश्य में इस्तेमाल किया जा सकता है कि एक और तरीका है - ResolveUsing :

Mapper.CreateMap<Person, Domain.Person>()
    .ForMember(dest => dest.Address, opt => opt.ResolveUsing( src => { return new Address() {Address1 = src.Address, City = src.City, State = src.State }; }))

यह भी मेरे लिए काम करने लगता है:

Mapper.CreateMap<PersonDto, Address>();
Mapper.CreateMap<PersonDto, Person>()
        .ForMember(dest => dest.Address, opt => opt.MapFrom( src => src )));

मूल रूप से, दोनों ऑब्जेक्ट्स के लिए dto से एक मैपिंग बनाएँ, और फिर इसे चाइल्ड ऑब्जेक्ट के लिए स्रोत के रूप में उपयोग करें।


https://github.com/omuleanu/ValueInjecter उपयोग https://github.com/omuleanu/ValueInjecter , यह चपटा और अप्रभावित करता है, और आपको जो कुछ भी चाहिए, वह डाउनलोड में एक asp.net mvc नमूना एप्लिकेशन है जहां सभी सुविधाओं का प्रदर्शन किया जाता है (यूनिट परीक्षण भी)


मैं यह प्रयोग कर रहा हूं

public static void Unflatten<TSource, TDestination, TMember>(this IMemberConfigurationExpression<TSource, TDestination, TMember> opt)
{
    var prefix = opt.DestinationMember.Name;
    var memberProps = typeof(TMember).GetProperties();
    var props = typeof(TSource).GetProperties().Where(p => p.Name.StartsWith(prefix))
        .Select(sourceProp => new
        {
            SourceProp = sourceProp,
            MemberProp = memberProps.FirstOrDefault(memberProp => prefix + memberProp.Name == sourceProp.Name)
        })
        .Where(x => x.MemberProp != null);
    var parameter = Expression.Parameter(typeof(TSource));

    var bindings = props.Select(prop => Expression.Bind(prop.MemberProp, Expression.Property(parameter, prop.SourceProp)));
    var resolver = Expression.Lambda<Func<TSource, TMember>>(
        Expression.MemberInit(Expression.New(typeof(TMember)), bindings),
        parameter);

    opt.ResolveUsing(resolver.Compile());
}

विन्यास

new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Person, PersonDTO>();
    cfg.CreateMap<PersonDTO, Person>().ForMember(x => x.HomeAddress, opt => opt.Unflatten());
});

मॉडल के

public class Person
{
    public string Name { get; set; }
    public Address HomeAddress { get; set; }
}

public class Address
{
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

AutoMapper समतल सम्मेलनों के बाद

public class PersonDTO
{
    public string Name { get; set; }
    public string HomeAddressLine1 { get; set; }
    public string HomeAddressLine2 { get; set; }
    public string HomeAddressCity { get; set; }
    public string HomeAddressState { get; set; }
    public string HomeAddressZipCode { get; set; }
}

शायद कई सुधार की जरूरत है लेकिन यह काम करता है ...


यह देर हो सकती है लेकिन आप इस तरह से ऑब्जेक्ट बनाने के लिए लैम्बडा एक्सप्रेशन का उपयोग करके इसे हल कर सकते हैं:

Mapper.CreateMap<Person, Domain.Person>()
        .ForMember(dest => dest.Address, opt => opt.MapFrom( src => { return new Address() {Address1 = src.Address, City = src.City, State = src.State }; }))

मेरे पास एक और उपाय है। मुख्य विचार यह है कि AutoMapper नेस्टेड ऑब्जेक्ट्स को सही तरीके से नाम देने पर नेस्टेड ऑब्जेक्ट्स को समतल करने का तरीका know : एक उपसर्ग के रूप में नेस्टेड ऑब्जेक्ट प्रॉपर्टी का नाम जोड़ना। आपके मामले के लिए पता उपसर्ग है:

public class PersonDTO
{
    public string Name { get; set; }
    public string AddressCity { get; set; }
    public string AddressState { get; set; }
    ...
}

तो नेस्टेड से चपटा करने के लिए परिचित मानचित्रण बनाने और फिर ReverseMap विधि का उपयोग करके AutoMapper को समझने की अनुमति मिलती है कि कैसे नेस्टेड ऑब्जेक्ट को अनफ्लैट किया जाए

CreateMap<Person, PersonDTO>()
   .ReverseMap();

बस इतना ही!