之前在園子閑逛的時候,發現許多關於automapper的文章,以及用aotufac+automapper合在一起用。當然發現大多數文章是將automapper的特點說出或將automapper幾處關鍵代碼放出。當然有過基礎的人看這種文章沒有什么問題,但是對於完全沒有基礎的小白來看完全是災難級別的(我就是),經常按着博文一點一點的寫,突然發現少了一部分導致代碼無法運行。在搜索各種文章之后,終於用自己的理解寫出了一個簡單的運用automapper的demo,日后待我對automapper理解加深會進一步更新。【此文章希望對想能初步運用automapper的小白寫出。當然也希望各位大牛提出意見】(關於autofac詳細講解)
0】首先看看automapper的介紹吧:
automapper是對象到對象的映射工具。在完成映射規則之后,automapper可以將源對象轉換為目標對象。
1】首先放出項目結構圖
由於此demo運用的是mvc三層+autofac實現依賴注入,所以文件中有三層以及ui層app_Start下的autoFacConfig.cs文件。之前有一篇博文詳細講解了autofac,所以這里只是簡單介紹一下代碼。主要目光放在mode層和automapper相關的文件。
2】首先貼出各層代碼
model文件下結構
可以看到model文件夾下有兩個內庫autoTS.Model和autoTS.ModelView(其實autoTS.ModelView下文件可以放到autoTS.Model中,剛剛寫的時候忘記了)
autoTS.Mode中system文件夾中文件是和數據庫中表一一對應。而autoTS.ModelView下system中文件則是和autoTS.Mode中system文件夾中文件對應(為了實現automapper的功能)將兩者進行對比一下
可以看到兩者的不同,明顯負責連接數據庫的model彼modelView多了一些標志(上傳csdn中代碼的時候忘記寫這些,可以下載demo和閱讀此博客)
然后autoTs.model層下DBContext.cs代碼(autoTS.Model層需要在nuget中引用EntityFramework)

public class DBContext : DbContext { public DBContext() : base("name=DatabaseTS") { }//配置文件中連接數據庫設置的name public DbSet<User> User { get; set; } public DbSet<UserType> UserType { get; set; } }
3】接下來是DAL文件的結構以及代碼(不是本文章主要內容值貼出代碼,不加以詳細說明)
先是idal層中的文件代碼(需要nuget中引用EntityFramework 和autoTS.Model)
IBaseDal.cs

//具體業務依賴於接口 public interface IBaseDal<TEntity> where TEntity : class { #region 1.0 增 void Add(TEntity model); #endregion #region 2.0 刪 void Delete(TEntity model, bool isAddedDbContext); #endregion #region 3.0 改 void Edit(TEntity model, string[] propertyNames); #endregion #region 4.0 查 #region 4.0.1 根據條件查詢 List<TEntity> QueryWhere(Expression<Func<TEntity, bool>> where); #endregion #endregion #region 5.0 統一保存 /// <summary> /// 統一將EF容器對象中的所有代理類生成相應的sql語句發給db服務器執行 /// </summary> /// <returns></returns> int SaveChanges(); #endregion }
system中User_IDAL.cs

public interface User_IDAL : IBaseDal<User> { }
然后是dal層中的代碼(需要引用EntityFramework 和autoTS.Model、autoTS.IDAL)
BaseDal.cs

public class BaseDal<TEntity> : IBaseDal<TEntity> where TEntity : class { //1.0 實例化EF上下文 DbContext db = BaseDBContent.GetCurrentThreadInstance(); //2.0 定義DbSet<T> 對象 public DbSet<TEntity> _dbset; //3.0 在構造函數的初始化_dbset public BaseDal() { _dbset = db.Set<TEntity>(); } #region 1.0 增 public virtual void Add(TEntity model) { //1.0 參數合法性驗證 if (model == null) { throw new Exception("BaseRepository泛型類中,新增操作的實體不能為空"); } //2.0 進行新增操作 _dbset.Add(model); } #endregion #region 2.0 刪 public virtual void Delete(TEntity model, bool isAddedDbContext) { //1.0 參數合法性驗證 if (model == null) { throw new Exception("BaseRepository泛型類中,刪除操作的實體不能為空"); } //2.0 進行刪除邏輯處理 if (!isAddedDbContext) { _dbset.Attach(model); } _dbset.Remove(model); } #endregion #region 3.0 改 /// <summary> /// 編輯,約定model 是一個自定義的實體,沒有追加到EF容器中的 /// </summary> /// <param name="model"></param> public virtual void Edit(TEntity model, string[] propertyNames) { //0.0 關閉EF的實體屬性合法性檢查 db.Configuration.ValidateOnSaveEnabled = false; //1.0 參數合法性驗證 if (model == null) { throw new Exception("BaseRepository泛型類中,編輯操作的實體不能為空"); } if (propertyNames == null || propertyNames.Length == 0) { throw new Exception("BaseRepository泛型類中,編輯操作的屬性數組必須至少有一個值"); } //2.0 將model追加到EF容器中的 DbEntityEntry entry = db.Entry(model); entry.State = EntityState.Unchanged; foreach (var item in propertyNames) { entry.Property(item).IsModified = true; } } #endregion #region 4.0 查 /// <summary> /// 帶條件查詢 /// </summary> /// <param name="where"></param> /// <returns></returns> public virtual List<TEntity> QueryWhere(Expression<Func<TEntity, bool>> where) { return _dbset.Where(where).ToList(); } #endregion #region 5.0 統一保存 /// <summary> /// 統一將EF容器對象中的所有代理類生成相應的sql語句發給db服務器執行 /// </summary> /// <returns></returns> public virtual int SaveChanges() { try { return db.SaveChanges(); } catch (Exception ex) { throw ex; } } #endregion }
BaseDBContent.cs

public class BaseDBContent { //獲取當前EF上下文的唯一實例 public static DbContext GetCurrentThreadInstance() { DbContext obj = CallContext.GetData(typeof(BaseDBContent).FullName) as DbContext; if (obj == null) { obj = new DBContext(); CallContext.SetData(typeof(BaseDBContent).FullName, obj); } return obj; } }
system中User_DAL.cs

public class User_DAL : BaseDal<User>, User_IDAL { }
4】bll文件中代碼和結構
ibll層代碼(此層需要引用autoTS.Model)
IBaseBLL.cs

public interface IBaseBLL<TEntity> where TEntity : class { #region 1.0 增 void Add(TEntity model); #endregion #region 2.0 刪 void Delete(TEntity model, bool isAddedDbContext); #endregion #region 3.0 改 /// <summary> /// 編輯,約定model 是一個自定義的實體,沒有追加到EF容器中的 /// </summary> /// <param name="model"></param> void Edit(TEntity model, string[] propertyNames); #endregion #region 4.0 查 /// <summary> /// 帶條件查詢 /// </summary> /// <param name="where"></param> /// <returns></returns> List<TEntity> QueryWhere(Expression<Func<TEntity, bool>> where); #endregion #region 5.0 統一保存 /// <summary> /// 統一將EF容器對象中的所有代理類生成相應的sql語句發給db服務器執行 /// </summary> /// <returns></returns> int SaveChanges(); #endregion }
system文件夾下User_IBLL.cs

public interface User_IBLL : IBaseBLL<User> { }
bll層中代碼(需要引用autoTS.Model、autoTS.IBLL、autoTS.IDAL)
BaseBLL.cs

public class BaseBLL<TEntity> : IBaseBLL<TEntity> where TEntity : class { protected IBaseDal<TEntity> dal = null; #region 1.0 增 public virtual void Add(TEntity model) { dal.Add(model); } #endregion #region 2.0 刪 public virtual void Delete(TEntity model, bool isAddedDbContext) { dal.Delete(model, isAddedDbContext); } #endregion #region 3.0 改 /// <summary> /// 編輯,約定model 是一個自定義的實體,沒有追加到EF容器中的 /// </summary> /// <param name="model"></param> public virtual void Edit(TEntity model, string[] propertyNames) { dal.Edit(model, propertyNames); } #endregion #region 4.0 查 /// <summary> /// 帶條件查詢 /// </summary> /// <param name="where"></param> /// <returns></returns> public virtual List<TEntity> QueryWhere(Expression<Func<TEntity, bool>> where) { return dal.QueryWhere(where); } #endregion #region 5.0 統一保存 /// <summary> /// 統一將EF容器對象中的所有代理類生成相應的sql語句發給db服務器執行 /// </summary> /// <returns></returns> public virtual int SaveChanges() { return dal.SaveChanges(); } #endregion }
system文件中User_BLL.cs

public class User_BLL : BaseBLL<User>, User_IBLL { User_IDAL dalSer; public User_BLL(User_IDAL dalSer) { base.dal = dalSer; this.dalSer = dalSer; } }
5】公共層all文件夾代碼以及結構(圈起來的都是要引用的,前面有紅線的則是在nuget中引用 注意引用mvc的版本必須和自己ui層mvc版本一致)
IOCDI.CS

using autoTS.IBLL.system; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Mvc; namespace autoTS.Mapperx.System { public class IOCDI : Controller { protected User_IBLL UserSer; protected UserType_IBLL UserTypeSer; } }
(本次重點)EntityExtMethod.cs中代碼是為了實現automapper

using AutoMapper; using autoTS.Model.System; using autoTS.ModelView.SystemView; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace autoTS.Mapperx { public static class EntityExtMethod { #region UserView-User public static UserView EntityMap(this User model) { //利用AutoMapper 來將 User 的屬性值動態拷貝到 UserView 類中對應的同名屬性值中 // 開始轉換 return Mapper.Map<User, UserView>(model); } public static User EntityMap(this UserView model) { //利用AutoMapper 來將 UserView 的屬性值動態拷貝到 User 類中對應的同名屬性值中 // 開始轉換 return Mapper.Map<UserView, User>(model); } #endregion #region UserTypeView-Type public static UserTypeView EntityMap(this UserType model) { //利用AutoMapper 來將 UserType 的屬性值動態拷貝到 UserTypeView 類中對應的同名屬性值中 // 開始轉換 return Mapper.Map<UserType, UserTypeView>(model); } public static UserType EntityMap(this UserTypeView model) { //利用AutoMapper 來將 UserTypeView 的屬性值動態拷貝到 UserType 類中對應的同名屬性 // 開始轉換 return Mapper.Map<UserTypeView, UserType>(model); } #endregion } }
6】最后來到ui層
方框里面是引用部分。而前面帶紅線的則是需要到nuget中引用(注意第二個autofac.integration.MVC是在nuegt中引用autofac.MVC5得到)
首先在app_Start中添加AutoFacConfig.cs(關於這部分內容,之前一份博客已經講過就不多重復)

using Autofac; using Autofac.Integration.Mvc; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web; using System.Web.Mvc; namespace WebApplication1.App_Start { public class AutoFacConfig { /// <summary> /// 負責調用autofac框架實現業務邏輯層和數據倉儲層程序集中的類型對象的創建 /// 負責創建MVC控制器類的對象(調用控制器中的有參構造函數),接管DefaultControllerFactory的工作 /// </summary> public static void Register() { //實例化一個autofac的創建容器 var builder = new ContainerBuilder(); //告訴Autofac框架,將來要創建的控制器類存放在哪個程序集 (IOCtsX.UI) Assembly controllerAss = Assembly.Load("WebApplication1"); builder.RegisterControllers(controllerAss); //告訴autofac框架注冊數據倉儲層所在程序集中的所有類的對象實例 Assembly respAss = Assembly.Load("autoTS.DAL"); //創建respAss中的所有類的instance以此類的實現接口存儲 builder.RegisterTypes(respAss.GetTypes()).AsImplementedInterfaces(); //告訴autofac框架注冊業務邏輯層所在程序集中的所有類的對象實例 Assembly serpAss = Assembly.Load("autoTS.BLL"); //創建serAss中的所有類的instance以此類的實現接口存儲 builder.RegisterTypes(serpAss.GetTypes()).AsImplementedInterfaces(); //創建一個Autofac的容器 var container = builder.Build(); //將MVC的控制器對象實例 交由autofac來創建 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } } }
然后再app_Start中添加AutoMapperConfig.cs。這部分一看就是為了實現automapper內容

using AutoMapper; using autoTS.Model.System; using autoTS.ModelView.SystemView; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WebApplication1.App_Start { public class AutoMapperConfig { public static void Initializex() { //Entity與DTO的映射 初始化映射的方向 (注冊) 寫在這里是因為只需要注冊一次, //放在C:\Users\Fates\source\repos\automapperTS\autoTS.Mapperx\EntityExtMethod.cs 中因為每次使用都會注冊從而報錯(只需要注冊一次) Mapper.Initialize(x => { x.CreateMap<User, UserView>(); //創建User映射到UserView x.CreateMap<UserView, UserType>(); //反之 x.CreateMap<UserType, UserTypeView>(); //創建UserType映射到UserTypeView x.CreateMap<UserTypeView, UserType>(); //反之 }); } } }
注意自己引用的automapper,高版本和低版本的寫法有些不同,如圖
如果不知道自己引用的是低版本還是高版本的話,就寫Mapper.CreateMap<user, userView>();看是否報錯,如果報錯則是高版本的automapper,使用左上圖寫法,否者用右上圖寫法。
寫完這些文件之后去Global.asax中進行注冊
最后,我們來到控制器,寫一個demo
最后來數據庫看看結構
【總結】由於博主技術渣渣,所以文章內容不是太深入。只是簡單介紹了如何簡單的使用automapper,日后待到這一塊深入了解之后,必將更新。此文章適合需要入門automapper的小白,跟着文章一步一步走必將寫出一個可運行的demo。因為項目的所有代碼和引用文件都已經做了詳細的說明。如果懶人黨的話,稍后會更新demo下載地址。同時也希望各位大牛的的意見與指點。