ITOO框架簡單瞭解
一、回顧三層
二、D層重構
我們在敲D層的時候,UserDAL和RoleDAL中都包含實現對資料庫的操作,也就是增刪改查,那麼我們可以將這些公共的東西抽象出來實現一個固定的功能的基類(BaseDAL),然後我們對其進行繼承操作。
- BaseDAL
public class BaseRepository<T> where T : class
{
//建立EF上下文
private LYZJEntities dbLYZJ = new LYZJEntities();
#region 實現對資料庫的修改功能+UpdateEntity+王娜+2016年1月9日16:38:30
/// <summary>
/// 實現對資料庫的修改功能+UpdateEntity+王娜+2016年1月9日16:38:30
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public bool UpdateEntity(T entity)
{
dbLYZJ.Set<T>().Attach(entity);
dbLYZJ.Entry<T>(entity).State = EntityState.Modified;
return dbLYZJ.SaveChanges() > 0;
}
#endregion
}
針對面向介面程式設計
三、B層重構
- BaseService類
在B層中的每個類,都有例項化D層的過程,現在我們將這個過程進行封裝,建立一個基類(BaseService)
public abstract class BaseService<T>where T:class,new()
{
public IDAL.IBaseRepository<T> CurrentRepository { get ; set; }
//建構函式
public BaseService()
{
SetCurrentRepository();//建構函式裡面去呼叫,設定當前DAL的抽象
}
public abstract void SetCurrentRepository();//必須由子類實現
}
- UserInfoService類
public class UserInfoService:BaseService<UserInfo>
{
public override void SetCurrentRepository()
{
CurrentRepository = DAL.UserInfoRepository;
}
public bool UpdateEntity(T entity)
{
return CurrentReository.UpdateEntity(entity);
}
}
因為,子類呼叫哪個D層,只有子類(UserInfoService)清楚,父類(BaseService)不知道,所以,我們呼叫一個抽象方法public abstract void SetCurrentRepository()讓子類自己進行實現;因為我們所有的D層類都間接的繼承於IBaseDAL,所以我們可以使用IBaseDAL類接收當前的DAL。
- 針對面向介面程式設計
四、B層對於D層的引用
之前,我們是B層直接呼叫D層,現在我們立一個數據層的統一入口——Factory來進行封裝。
- RepositoryFactory
public class RepositoryFactory
{
#region 王娜+2016年1月10日16:30:59
public static IUserInfoRepository UserInfoRepository
{
get { return new UserInfoRepository(); }
}
#endregion
#region 王娜+2016年1月10日16:31:12
public static IRoleRepository RoleRepository
{
get { return new RoleRepository(); }
}
#endregion
- 業務邏輯層例項化D層的程式碼:
private IUserInfoRepository _userInfoRepository = RepositoryFactory.UserInfoRepository;
五、D層對EF上下文的管理
在此之前,我們先了解一下EF,EF是跟蹤實體變化,然後將此變化對映到資料庫的表中。EF上下文(DbContext)是與資料庫的一次會話,我們要保證DbContext的執行緒唯一性。
原因
如何保證EF上下文的唯一性呢?我們建立一個EFContextFactory工廠,讓工廠中的GetCurrentDbContext()方法返回例項。
- EFContextFactory
public partial class EFContextFactory
{
/// <summary>
/// 幫我們返回當前執行緒內的資料庫上下文,如果當前執行緒內沒有上下文,那麼建立一個上下文,並保證
/// 上下文是例項線上程內部唯一
/// 在EF4.0以前使用ObjectsContext物件
/// </summary>
/// <returns></returns>
public static DbContext GetCurrentDbContext()
{
//當第二次執行的時候直接取出執行緒嘈裡面的物件
//CallContext:是執行緒內部唯一的獨用的資料槽(一塊記憶體空間)
//資料儲存線上程棧中
//執行緒內共享一個單例
DbContext dbcontext = CallContext.GetData("DbContext") as DbContext;
//判斷執行緒裡面是否有資料
if (dbcontext == null) //執行緒的資料槽裡面沒有次上下文
{
dbcontext = new DataModelContainer(); //建立了一個EF上下文
//儲存指定物件
CallContext.SetData("DbContext", dbcontext);
}
return dbcontext;
}
}
- BaseDAL修改為:
public partial class BaseDAL<T> where T : class
{
//EF上下文的例項保證,執行緒內唯一
//例項化EF框架
//DataModelContainer db = new DataModelContainer();
//修改部分
//獲取的實當前執行緒內部的上下文例項,而且保證了執行緒內上下文例項唯一
private DbContext db = EFContextFactory.GetCurrentDbContext();
}
- DbSession(之前的工廠RepositoryFactory):
public class DbSession //代表應用程式跟資料庫之間的一次會話,也是資料庫訪問層的統一入口
{
public IDAL.IRoleDAL RoleDAL
{
get
{
return new RoleDAL();
}
}
public IDAL.IUserInfoDAL UserInfoDAL
{
get
{
return new UserInfoDAL();
}
}
public int SaveChanges() //UintWork單元工作模式
{
//呼叫EF上下文的SaveChanges的方法
return DAL.EFContextFactory.GetCurrentDbContext().SaveChanges();
}
}
現在,我們實現了對於EF上下文的執行緒唯一性管理,那麼為什麼我們要在DbSession中呼叫EF上下文的SaveChanges方法呢?這裡的SaveChanges方法相當於直接把當前執行緒內部所有實體的改變提交到資料庫裡面。當我們把BaseDAL中增刪改方法中的SaveChanges方法刪除掉時,我們的資料庫訪問層雖然呼叫了增刪改的方法,但是沒有真正的儲存到資料庫裡面,這時,因為RepositoryFactory是資料層的統一入口,將SaveChanges全部給放到DbSession中去實現,DbSession我們就能夠看成一個真正的會話了。也就是說我們在前面呼叫了很多次的增刪改的實體之後(操作很多表),而只需要去DbSession中呼叫一個SaveChanges方法,就可以把所有的表實體的變化都放到資料庫中去。
- D層與EF上下文的關係
- BaseService修改:
public abstract class BaseService<T> where T : class,new()
{
//在呼叫這個方法的時候必須給他賦值
public IDAL.IBaseRepository<T> CurrentRepository { get; set; }
//DbSession的存放
public DbSession _DbSession = new DbSession();
//基類的建構函式
public BaseService()
{
SetCurrentRepository(); //建構函式裡面呼叫了此設定當前倉儲的抽象方法
}
//構造方法實現賦值
public abstract void SetCurrentRepository(); //約束子類必須實現這個抽象方法
}
所以DbSession兼顧了簡單工廠模式和SaveChange方法。然後因為DbSession就是我們整個資料庫訪問層的入口,那麼我們DbSession也必須由一個介面的約束,那麼我們在資料庫訪問介面層(LYZJ.UserLimitMVC.IDAL類庫)加個介面約束,新建介面IDbSession。
業務邏輯層DbSession執行緒內唯一
(1)通過前面的部落格我們知道我們將資料庫訪問層的BaseDAL(倉儲)使用簡單工廠來實現了執行緒內唯一的定義,程式碼如下:
//獲取的實當前執行緒內部的上下文例項,而且保證了執行緒內上下文例項唯一
private DbContext db = EFContextFactory.GetCurrentDbContext();
(2)按照上面的說法的話,那麼我們的業務邏輯層來獲取DbSession的時候也是使用簡單工廠來實現執行緒內唯一,那麼我們修改DbSession的定義如下:
public abstract class BaseService<T> where T : class,new()
{
//DbSession的存放
public IDbSession _dbSession = DbSessionFactory.GetCurrentDbSession();
}
最後看一下DbSessionFactory的程式碼:
public class DbSessionFactory
{
/// <summary>
/// 保證了執行緒內DbSession例項唯一
/// </summary>
/// <returns></returns>
public static IDbSession GetCurrentDbSession()
{
IDbSession _dbSession = CallContext.GetData("DbSession") as IDbSession;
if (_dbSession == null)
{
_dbSession = new DbSession();
CallContext.SetData("DbSession", _dbSession);
}
return _dbSession;
}