回到目錄
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工具裡的通用作法,即先拿出對象,再為指定屬性賦新的值,最後提交到數據庫!
感謝您的閱讀!
回到目錄