其實我對微軟出的Linq to Sql,以及Linq to Entity這兩個產品興趣都不大,不太喜歡那種開發模式,主要原因如下:
1:自動生成的那堆代碼,不利於平時的分層模式,將實體以及存儲邏輯混合在一起總覺的不是那麼回事;
2:對於編寫測試用例不是那麼友好,全部邏輯都在一起,無法拆分測試,比如只想測試代碼邏輯,不需要連接真正的數據庫等。
3:在排除程序BUG時,還是習慣於看直觀的SQL,這樣在數據庫中調試起來更加容易些,可能是個人習慣問題;
4:據説性能上存在一定缺陷,本人並未測試過,道聽途説而已。
之所以這次想嘗試一次,主要基於兩點:首先我現在接手的一個項目是用EF編寫的,其次就是EF 4.2能夠將原來混合在一起的代碼給分離開,説的官方點,這個分離功能叫POCO,英文全名是Plain Old CLR Object,翻譯成中文是簡單傳統的CLR對象。總之最新的EF允許開發人員手工編寫更多代碼,不再一味的依賴代碼自動生成。
第一:如何安裝EF 4.2?
我電腦上原來安裝的是EF 4.0,這次選擇的是通過NuGet方式安裝。
1:首先從VS菜單上選擇工具,然後選擇擴展管理,如下圖。
2:在彈出框的左側選擇Online,然後在右上角搜索Nuget,最後進行安裝。
,
3:安裝NUGET後,我們在工程的引用中點擊右鍵,就會多出一項來,如下所示。
4:添加EF引用。點擊上圖中的最後一項,搜索EntityFramework,就會看到最新的EF了,選擇進行添加即可。
第二:創建EF程序。
我採用的是最早的模式,即先有數據庫,然後再有程序的模式,程序分了如下幾層:
1:ModelFirstSample.DAL,這是數據層,用於存放與數據庫打交道的邏輯;
先按正常流程添加一個ADO.NET Entity Data Model,按步就班,一步一步下來就行。這樣會生成一個.edmx的文件。
然後打開edmx文件,點擊右鍵選擇添加代碼生成項,在彈出的菜單中選擇Db context那項,接下來會生成PersonModel.tt,PersonModel.Context.tt兩文件,對應的edmx下面的自動生成的代碼已經為空了。
2:ModelFirstSample.Model,實體層,將EF生成的.edmx,.tt文件放在這,與存儲邏輯分離;
將第一步生成的PersonModel.edmx,PersonModel.tt添加到工程下面,同時刪除原文件,這樣就實現了實體層與存儲邏輯的分離。
3:ModelFirstSample.BLL,業務邏輯層,不用多説;
4:ModelFirstSample.Service,服務層,對於業務邏輯層的進一步包裝;
5:ModelFirstSample.ConsoleApp,UI層。
第三:EF中的開發模式之Repository。
在實際項目中,如果希望能夠對存儲邏輯有一定的控制,於是就有了repository模式的出現,也就是對原始存儲邏輯的一種封裝。
1:在接口層中創建一個通用的存儲接口IRepository<T>,便於邏輯複用。
public interface IRepository<T> where T : class, new()
{
T Create();
T Update(T entity);
T Insert(T entity);
void Delete(T entity);
T Find(params object[] keyValues);
List<T> FindAll();
}
2:在DAL層中創建一個實現了IRepository<T>接口的RepositoryBase<T>基類,主要的就是需要提供一個DbContext,基本思想就是利用DbContext的Set<T>構造的類型來提供封裝,這裏就不做多的説明了,我這裏為了簡單,使用了默認構造方法,FacePerfEntities是添加edmx時生成的類。
View Code
public class RepositoryBase<T> : IRepository<T> where T : class,new()
{
public DbContext context;
public RepositoryBase(DbContext _context)
{
this.context = _context;
}
public RepositoryBase()
{
this.context = new FacePerfEntities();
}
#region IRepository<T> 成員
public T Create()
{
return context.Set<T>().Create();
}
public T Update(T entity)
{
if (context.Entry<T>(entity).State == EntityState.Modified)
context.SaveChanges();
return entity;
}
public T Insert(T entity)
{
context.Set<T>().Add(entity);
context.SaveChanges();
return entity;
}
public void Delete(T entity)
{
context.Set<T>().Remove(entity);
context.SaveChanges();
}
public T Find(params object[] keyValues)
{
return context.Set<T>().Find(keyValues);
}
public List<T> FindAll()
{
return context.Set<T>().ToList();
}
#endregion
}
3:在接口層中創建一個關於員工的接口:IEmployeeRepository<T>
public interface IEmployeeRepository<T>
{
List<T> SearchEmployee();
}
4:在業務邏輯層中創建關於員工的專用類:EmployeeRepositoryBLL。
public class EmployeeRepositoryBLL : IEmployeeRepository<Employee>
{
EmployeeRepository repository = new EmployeeRepository();
public List<Employee> SearchEmployee()
{
return repository.FindAll();
}
}
5:在服務層中創建員工的服務類,由於這只是測試用,所以服務類起的作用並不明顯,至於為什麼有服務層,是為了將UI層與業務邏輯層分離等等眾多原因。
View Code
public class EmployeeRepositoryService
{
EmployeeRepositoryBLL repositoryEmployee=null ;
public EmployeeRepositoryService()
{
repositoryEmployee = new EmployeeRepositoryBLL();
}
public List<Employee> SearchEmployee()
{
return this.repositoryEmployee.SearchEmployee();
}
}
6:最後就是UI了。
View Code
static void Main(string[] args)
{
EmployeeRepositoryService ers = new EmployeeRepositoryService();
var list = ers.SearchEmployee();
var people = from p in list
orderby p.CreatedOn
select p;
Console.WriteLine("All People:");
foreach (var person in people)
{
Console.WriteLine("- {0}", person.ChineseName);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
補充説明:
1:添加完edmx後,以及完成添加代碼生成項後,查詢PersonModel.Context.cs,代碼如下:
public FacePerfEntities()
: base("name=FacePerfEntities")
{
}
構造函數中的參數FacePerfEntities,其實就對應EF數據庫連接串的節點名稱。
2:添加完edmx後,在DAL層還會有一個packages.config文件,這個文件不用發佈到UI程序下面,也不影響程序運行,只需要將連接串對應的節點複製到UI配置文件中即可。
總結: 經過上面的改造,已經越來越適合實際項目了,EF在不斷改進,我想在一些小型項目中快速開發倒是蠻適合的。