2015-08-20 8 views
7

यह एक लंबा है।ऑटोमैपर नक्शा गुणों के बजाय नया उदाहरण बना रहा है

तो, मेरे पास एक मॉडल और एक दृश्य मॉडल है जिसे मैं AJAX अनुरोध से अपडेट कर रहा हूं। -> UserViewModel (और पीछे) मानचित्रण

private User updateUser(UserViewModel entityVm) 
{ 
    User existingEntity = db.Users.Find(entityVm.Id); 
    db.Entry(existingEntity).Collection(x => x.UserPreferences).Load(); 

    Mapper.Map<UserViewModel, User>(entityVm, existingEntity); 
    db.Entry(existingEntity).State = EntityState.Modified; 

    try 
    { 
     db.SaveChanges(); 
    } 
    catch 
    { 
     throw new DbUpdateException(); 
    } 

    return existingEntity; 
} 

मैं automapper तो उपयोगकर्ता के लिए की तरह कॉन्फ़िगर किया है: वेब एपीआई नियंत्रक viewmodel, जो मैं तो नीचे की तरह AutoMapper का उपयोग कर मौजूदा मॉडल अपडेट प्राप्त करता है।

Mapper.CreateMap<User, UserViewModel>().ReverseMap(); 

मैं मॉडल/ViewModel के एक सदस्य के एक अलग वस्तु का एक ICollection है उस के साथ समस्या हो रही है (ध्यान दें कि स्पष्ट रूप से विपरीत नक्शे की स्थापना और ReverseMap को छोड़ते हुए एक ही व्यवहार दिखाता है) :

[DataContract] 
public class UserViewModel 
{ 
    ... 
    [DataMember] 
    public virtual ICollection<UserPreferenceViewModel> UserPreferences { get; set; } 
} 

इसी मॉडल की तरह है:

public class User 
{ 
    ... 
    public virtual ICollection<UserPreference> UserPreferences { get; set; } 
} 

समस्या:

उपयोगकर्ता और UserViewModel वर्गों में से हर संपत्ति को सही ढंग से नक्शे, UserPreferences/UserPreferenceViewModels की ICollections ऊपर दिखाए गए के अलावा। जब ये संग्रह नक्शा गुणों के बजाय व्यूमोडेल से मॉडल में मानचित्र होते हैं, तो ViewModel गुणों के साथ मौजूदा ऑब्जेक्ट को अपडेट करने के बजाय, UserPreference ऑब्जेक्ट का एक नया उदाहरण ViewModel से बनाया गया है।

मॉडल:

public class UserPreference 
{ 
    [Key] 
    public int Id { get; set; } 

    public DateTime DateCreated { get; set; } 

    [ForeignKey("CreatedBy")] 
    public int? CreatedBy_Id { get; set; } 

    public User CreatedBy { get; set; } 

    [ForeignKey("User")] 
    public int User_Id { get; set; } 

    public User User { get; set; } 

    [MaxLength(50)] 
    public string Key { get; set; } 

    public string Value { get; set; } 
} 

और इसी ViewModel

public class UserPreferenceViewModel 
{ 
    [DataMember] 
    public int Id { get; set; } 

    [DataMember] 
    [MaxLength(50)] 
    public string Key { get; set; } 

    [DataMember] 
    public string Value { get; set; } 
} 

और automapper विन्यास:

Mapper.CreateMap<UserPreference, UserPreferenceViewModel>().ReverseMap(); 

//also tried explicitly stating map with ignore attributes like so(to no avail): 

Mapper.CreateMap<UserPreferenceViewModel, UserPreference>().ForMember(dest => dest.DateCreated, opts => opts.Ignore()); 

जब एक उपयोगकर्ता के लिए एक UserViewModel इकाई मानचित्रण, UserPreferenceViewModels की ICollection भी है उपयोगकर्ता के संदर्भों के उपयोगकर्ता के आईसीलेक्शन को मैप किया गया, जैसा कि इसे करना चाहिए।

हालांकि

, जब ऐसा होता है, इस तरह के "DateCreated", "CreatedBy_Id", और "user_id" के रूप में अलग-अलग UserPreference ऑब्जेक्ट के गुणों के रूप में अगर एक नई वस्तु अलग-अलग प्रॉपर्टी के बजाय बनाई गई है प्रतिलिपि बनाई जा रही nulled मिलता है।

यह आगे जब एक UserViewModel संग्रह में केवल 1 UserPreference वस्तु है कि मानचित्रण के रूप में सबूत के तौर पर दिखाया गया है, जब DbContext निरीक्षण, वहाँ नक्शा बयान के बाद दो स्थानीय UserPreference वस्तुओं रहे हैं। एक जो व्यूमोडेल से बनाया गया एक नया ऑब्जेक्ट प्रतीत होता है, और वह मौजूदा मॉडल से मूल है।

मैं व्यूमोडेल के संग्रह से नए सदस्यों को तत्काल करने के बजाय, स्वचालित मॉडल के संग्रह के सदस्यों को कैसे अपडेट कर सकता हूं? मुझसे यहां क्या गलत हो रहा है?

स्क्रीनशॉट मैपर के पहले/बाद में प्रदर्शित करने के लिए।मानचित्र()

Before

After

+0

आप इतना है कि संग्रह एक ही होने के रूप में उन्हें पहचान कर सकते हैं में 'UserPreference' और' 'UserPreferenceViewModel' GetHashCode' ओवरराइड करने के लिए आवश्यकता हो सकती है: दुर्भाग्य से, यह एक मैनुअल प्रक्रिया है। हो सकता है कि automapper में कुछ जादू है लेकिन मुझे संदेह है – HaroldHues

+0

युप, CreateMap लाइन के लिए गलत पंक्ति को प्रतिलिपि/चिपकाया जाना चाहिए। मैं वर्तमान में GetHashCode ओवरराइड में देख रहा हूं, अगर कुछ भी मिलता है तो मैं वापस रिपोर्ट करूंगा। आपकी सहायता के लिए धन्यवाद. –

+0

आपको ViewModel से अपनी इकाई या डोमेन मॉडल में मानचित्र करने के लिए ऑटोमैपर का उपयोग करके वापस कदम और रोकना होगा। इसके लिए ऑटोमैपर नहीं बनाया गया था और उम्मीद के अनुसार काम नहीं करेगा। ऑटोमैपर ** का उपयोग करें ** केवल Entity/Domain Model से ViewModel/DTO/BindingModel पर मानचित्र के लिए, ** ** कहीं भी नहीं। ऐसा करने से ऑटोमैपर लेखक – Tseng

उत्तर

9

यह जहाँ तक मुझे पता है हूँ AutoMapper की एक सीमा है अधिक पाश करने के लिए कुछ तर्क लागू होता है। यह ध्यान में रखना उपयोगी है कि लाइब्रेरी लोकप्रिय मॉडलों और इकाइयों को देखने/देखने के लिए लोकप्रिय रूप से उपयोग की जाती है, लेकिन यह किसी भी वर्ग को किसी अन्य वर्ग में मैप करने के लिए एक सामान्य पुस्तकालय है, और इस तरह, सभी विलक्षणताओं को ध्यान में रखता नहीं है इकाई फ्रेमवर्क की तरह एक ओआरएम।

तो, यहां क्या हो रहा है इसका स्पष्टीकरण यहां दिया गया है। जब आप ऑटोमैपर के साथ किसी अन्य संग्रह में संग्रह को मैप करते हैं, तो आप सचमुच संग्रह मैपिंग कर रहे हैं, न कि उस संग्रह में आइटम्स के मानों को समान संग्रह में आइटमों के मानों पर। पूर्व-निरीक्षण में, यह समझ में आता है क्योंकि ऑटोमैपर के पास यह सुनिश्चित करने के लिए कोई भरोसेमंद और स्वतंत्र तरीका नहीं है कि इसे किसी संग्रह में किसी अन्य आइटम को किसी दूसरे स्थान पर कैसे रखा जाए: आईडी द्वारा? कौन सी संपत्ति आईडी है? शायद नाम मिलना चाहिए?

तो, क्या हो रहा है यह है कि आपकी इकाई पर मूल संग्रह पूरी तरह से ब्रांड नए आइटम उदाहरणों से बना एक नया संग्रह है। कई स्थितियों में, यह कोई समस्या नहीं होगी, लेकिन जब आप एंटीटी फ्रेमवर्क में परिवर्तन ट्रैकिंग के साथ गठबंधन करते हैं, तो अब आपने संकेत दिया है कि संपूर्ण मूल संग्रह हटा दिया जाना चाहिए और इकाइयों के एक नए सेट के साथ प्रतिस्थापित किया जाना चाहिए। जाहिर है, यह वही नहीं है जो आप चाहते हैं।

तो, इसे कैसे हल करें? खैर, दुर्भाग्य से, यह दर्द का थोड़ा सा है। पहला कदम AutoMapper बताने के लिए पूरी तरह से संग्रह की अनदेखी करने के लिए है जब मानचित्रण:

Mapper.CreateMap<User, UserViewModel>(); 
Mapper.CreateMap<UserViewModel, User>() 
    .ForMember(dest => dest.UserPreferences, opts => opts.Ignore()); 

सूचना है कि मैं इस दो नक्शे में टूट गया। अपने दृश्य मॉडल पर मैप करते समय आपको संग्रह को अनदेखा करने की आवश्यकता नहीं है। इससे कोई समस्या नहीं आएगी क्योंकि ईएफ उस पर नज़र रख रहा है। यह केवल तभी महत्वपूर्ण होता है जब आप अपनी इकाई वर्ग में वापस मैप कर रहे हों।

लेकिन, अब आप उस संग्रह को मैपिंग नहीं कर रहे हैं, तो आप आइटमों पर मूल्यों को वापस कैसे प्राप्त करते हैं?

foreach (var pref in model.UserPreferences) 
{ 
    var existingPref = user.UserPreferences.SingleOrDefault(m => m.Id == pref.Id); 
    if (existingPref == null) // new item 
    { 
     user.UserPreferences.Add(Mapper.Map<UserPreference>(pref)); 
    } 
    else // existing item 
    { 
     Mapper.Map(pref, existingPref); 
    } 
} 
1

AutoMapper source file कि सभी ICollection (अन्य बातों के अलावा) को संभालती है और ICollection Mapper के अनुसार:

संग्रह Clear() के लिए एक कॉल द्वारा मंजूरी दे दी है तो फिर जोड़ा , जहां तक ​​मैं देख सकता हूं कि ऑटोमैपर इस समय मैपिंग स्वचालित रूप से करने में सक्षम नहीं होगा।

मैं संग्रह और AutoMapper.Map होते हैं कि एक ही

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