C#扩展方法应用:数据模型映射

在 ASP.NET 实际开发中,C# 扩展方法使用非常普遍,但是很少有熟练使用它进行数据模型转化。类似这样情形比较常见,即实体数据(通常为数据表)模型 User 与参数(通常为方法参数)模型 UserModel 映射,常见的做法是,在每个(模型转化)方法中将 User 的属性跟 UserModel 的属性进行一一赋值映射,但此法存在诸多弊端,主要是重复赋值繁琐,不便于系统后期维护扩展。

显然,上文描述过于抽象,下面举例说明。假设存在两个实体数据模型 User 和 UserProfile,其中 User 为用户基本信息,UserProfile 为用户详细信息,模型其它属性从略,如下代码:

namespace Demo 
{ 
   /// <summary> 
   ///  
   /// </summary> 
   public class User 
   { 
       public string Name { get; set; } 
       public string Surname { get; set; } 
       public string UserName { get; set; } 
       public string Password { get; set; } 
       public Guid Uid { get; set; } 
   } 
   /// <summary> 
   ///  
   /// </summary> 
   public class UserProfile 
   { 
       public Guid Id { get; set; } 
       public string IdNumber { get; set; } 
       public int? CompanyId { get; set; } 
       public Address Address { get; set; } 
   } 
}

通常情况下,在进行 CURD 时,会是这样做:

namespace Demo 
{ 
   public class UserStore 
   { 
       public virtual async Task CreateAsync(UserInfo userInfo) 
       { 
           var user = new User() 
           { 
               Uid = userInfo.Uid, 
               Name = userInfo.Name, 
               Password = userInfo.Password, 
               UserName = userInfo.UserName, 
               Surname = userInfo.Surname, 
           }; 
           var userProfile = new UserProfile() 
           { 
               CompanyId = userInfo.CompanyId, 
               Address = userInfo.Address, 
               Id = userInfo.Uid, 
               IdNumber = userInfo.IdNumber 
           }; 
           await _userStore.CreateAsync(user); 
           await _userProfileStore.CreateAsync(userProfile); 
       } 
   } 
}

即对每一个实体数据模型属性分别赋值映射,对一个这样的操作无可厚非,但进行多个此类操作时,就会出现上述弊端。为了解决这个问题,我们可以建立一个UserExtensions扩展方法,如下:

namespace Demo 
{ 
   internal static class UserExtensions 
   { 
       public static UserProfile ToUserProfile(this UserInfo userInfo) 
       { 
           return userInfo == null 
               ? null : new UserProfile() 
               { 
                   CompanyId = userInfo.CompanyId, 
                   Address = userInfo.Address, 
                   Id = userInfo.Uid, 
                   IdNumber = userInfo.IdNumber 
               }; 
       } 
       public static User ToUser(this UserInfo userInfo) 
       { 
           return userInfo == null 
               ? null : new User() 
               { 
                   Uid = userInfo.Uid, 
                   Name = userInfo.Name, 
                   Password = userInfo.Password, 
                   UserName = userInfo.UserName, 
                   Surname = userInfo.Surname, 
               }; 
       } 
       public static UserInfo AssignTo(this User user, UserInfo userInfo) 
       { 
           if (userInfo == null) 
           { 
               userInfo = new UserInfo(); 
           } 
           if (user == null) 
           { 
               return userInfo; 
           } 
           userInfo.Uid = user.Uid.HasValue ? user.Uid.Value : Guid.Empty; 
           userInfo.Name = user.Name; 
           userInfo.Password = user.Password; 
           userInfo.UserName = user.UserName; 
           userInfo.Surname = user.Surname; 
           return userInfo; 
       } 
       public static UserInfo AssignTo(this UserProfile userProfile, UserInfo userInfo) 
       { 
           if (userInfo == null) 
           { 
               userInfo = new UserInfo(); 
           } 
           if (userProfile == null) 
           { 
               return userInfo; 
           } 
           userInfo.CompanyId = userProfile.CompanyId; 
           userInfo.Address = userProfile.Address; 
           userInfo.Uid = userProfile.Id; 
           userInfo.IdNumber = userProfile.IdNumber; 
           return userInfo; 
       } 
       public static UserInfo AssignTo(this UserProfile userProfile) 
       { 
           return AssignTo(userProfile, null); 
       } 
       public static UserInfo AssignTo(this User user) 
       { 
           return AssignTo(user, null); 
       } 
   } 
}

那么上述实例中 CreateAsync 变成如下方法:

namespace Demo 
{ 
   public class UserStore 
   { 
           ……             
           public virtual async Task CreateAsync(UserInfo userInfo) 
       { 
           var user = userInfo.ToUser(); 
           var userProfile = userInfo.ToUserProfile(); 
           await _userStore.CreateAsync(user); 
           await _userProfileStore.CreateAsync(userProfile); 
       } 
   } 
}

是不是很简洁?该做法优点远不止这些,最为典型的是,若后期需要对 User 和 UserProfile 进行扩展,添加(或减少)字段,只需要维护UserExtensions扩展方法,而不需要去维护每个 CURD 方法。

最后,请思考一下UserExtensions扩展类中的 AssignTo 有什么作用?

《C#扩展方法应用:数据模型映射》的相关评论

发表评论

必填项已用 * 标记,邮箱地址不会被公开。