基礎才是重中之重~AutoMapper為已有目標物件對映

張佔嶺發表於2015-11-13

回到目錄

AutoMapper各位一定不會陌生,大叔之前的文章中也提到過,曾經也寫過擴充套件方法,以方便程式開發人員去使用它,而在最近,大叔在一個API專案裡,在一個POST請求由DTO物件為實體物件賦值時,出現了一個問題,使用大叔不得不對原有擴充套件方法再進行二次的補充。

事情是這樣的,有一個DTO物件RequestUserInfo和一個資料庫實體物件UserInfo,在進行POST時,將RequestUserInfo物件的值需要賦給UserInfo物件,我們知道DTO物件是根據介面要求從UserInfo裡提取的,它的屬性要少於UserInfo,這在GET請求時,沒有出現任何問題(由userinfo到RequestUserInfo的對映),把對應的屬性值賦到了DTO物件上面,百在POST時,由於DTO物件的屬性少,所以,UserInfo的某些屬性沒有被賦到值,出現了Null。

   /// <summary>
    /// DTO 使用者-請求引數
    /// 輸入引數各屬性都是可空的,為空時不去驗證,並且查詢時不去構造查詢條件
    /// </summary>
    public class RequestUserInfo : RequestBase
    {
        public int? Id { get; set; }
        [MaxLength(10, ErrorMessage = "使用者名稱最多為10個字元")]
        public string UserName { get; set; }
        [EmailAddress(ErrorMessage = "Email地址不是合法的")]
        public string Email { get; set; }
        [MaxLength(20, ErrorMessage = "使用者名稱最多為20個字元")]
        public string RealName { get; set; }
    }
    public class UserInfo : Entity
    {
        [DisplayName("使用者名稱"), Required]// StringLength(50, MinimumLength = 4, ErrorMessage = "使用者名稱只能由~50個字元組成")
        public string UserName { get; set; }
        [DisplayName("真實姓名"), Required]//StringLength(30, MinimumLength = 6, ErrorMessage = "真實姓名只能由6~30個字元組成")
        public string RealName { get; set; }
        [DisplayName("密碼"), Required]// StringLength(20, MinimumLength = 6, ErrorMessage = "密碼由6~20個字元組成")
        public string Password { get; set; }
        [DisplayName("電子郵件"), Required, EmailAddress]
        public string Email { get; set; }
    }

以上是兩個物件的內容,在AutoMapper的概念裡,在GET請求時,UserInfo相當於TSource源物件,RequestUserInfo相當於TResult目標物件,而在POST請求時,這個正好相反,所以我們之前定義的擴充套件方法就有問題了,它會將UserInfo裡的某些屬性變成null,這是正常的,因為在進行AutoMapper時,如果你不給它傳目標物件,它會自動構建一個新物件。

擴充套件之前的方法,它AutoMapper支援為已有目標物件賦值

 

        /// <summary>
        /// 為已經存在的物件進行automapper
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="self"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static TResult MapTo<TResult>(this object self, TResult result)
        {
            if (self == null)
                throw new ArgumentNullException();
            Mapper.CreateMap(self.GetType().UnderlyingSystemType, typeof(TResult));
            return (TResult)Mapper.Map(self, result, self.GetType(), typeof(TResult));

        }

 

這樣在程式呼叫時,會把已經存在的物件result以引數的形式傳入,如下程式碼

   public void Update(RequestUserInfo request)
        {
            var entity = userRepository.GetModel().FirstOrDefault(i => i.Id == request.Id);
            request.MapTo<UserInfo>(entity);
            userRepository.Update(entity);
        }

這時entity是從資料庫裡拿出來的完整資料,再把它的DTO屬性進行自動對映賦值,最後把賦值後的物件進行更新!

上面是EF,LINQ這些ORM工具裡的通用作法,即先拿出物件,再為指定屬性賦新的值,最後提交到資料庫!

感謝您的閱讀!

回到目錄

 

相關文章