Repository模式之前
如果我們用最原始的EF進行設計對每個實體類的“C(增加)、R(讀取)、U(修改)、D(刪除)”這四個操作。
第一個:先來看看查詢,對於實體類簡單的查詢操作,每次都是這樣的過程會在代碼中擁有大量的重復 極為類似的代碼段。
using (var db = new EFContext("EFContext")) { var persons = db.Persons.Where(t => t.PersonName == "aehyok").OrderByDescending(t => t.PersonId).ToList(); foreach (var p in persons) { Console.WriteLine("The PersonName is {0} and Age {1}", p.PersonName, p.Age); } } Console.ReadLine();
第二個:對於實體類的添加操作。
using (var db = new EFContext()) { var stephen = new Person { PersonName="aehyok0001", Age=25, Address="深圳南山", Email="aehyok@163.com" }; db.Persons.Add(stephen); db.Persons.Attach(stephen); db.Entry(stephen).State = EntityState.Unchanged; ////同上面db.Persons.Attach(stephen);作用是一樣的 var jeffrey = new Person { PersonName = "aehyok0002", Age = 25, Address = "深圳寶安", Email = "Leo@163.com" }; db.Entry(jeffrey).State = EntityState.Added; db.SaveChanges(); }
第三個:同理,刪除操作如下。
using (var db = new EFContext()) { var person = db.Persons.Where(m => m.PersonId == 4).FirstOrDefault(); db.Persons.Remove(person); db.SaveChanges(); }
第四個:同理,修改操作如下。
using (var db = new EFContext()) { var person = db.Persons.Where(m => m.PersonId == 4).FirstOrDefault(); db.Persons.Remove(person); db.SaveChanges(); }
以上基於一個實體類簡單的CURD操作,當然對於查詢千變萬化。在數據訪問層,我們可以專門的為每個類進行封裝業務處理類,但是其中類與類之間相同或類似的代碼段太多,對於編碼人員來說,更是浪費時間,同樣的代碼,要在項目的不同使用地方,進行多次的復制修改幾個代碼字段即可使用,那么我們為什么不進行簡單的封裝處理,來讓這一過程變得更加簡單,且使我們的代碼變得更為優雅,讓開發人員的維護操作更為簡單,也更易於擴展。基於以上考慮引出了我們的Repository設計模式。
Repository設計模式
在《企業架構模式》中,譯者將Repository翻譯為資源庫。給出如下說明:通過用來訪問領域對象的一個類似集合的接口,在領域與數據映射層之間進行協調。
那么基於Rspository模式,數據訪問層無非就是對數據進行增刪改查,其中增、刪、改等我們可以抽象出來寫一個公共的接口或抽象類來定義這些方法,並采用一個基類實現這些方法,這樣該基類派生的子類都會繼承增、刪、改這些方法,這樣我們就避免了每個實體都要重復實現這些方法。一句話概括就是:通過接口 泛型 與ORM結合 實現了數據訪問層更好的復用。
Repository代碼實現
1.EF實例數據操作上下文對象
主要進行初始化數據庫,並進行設置自動更新數據庫
public class EFContext:DbContext { public EFContext() : base("default") { Database.SetInitializer<EFContext>(new MigrateDatabaseToLatestVersion<EFContext,EFDbMigrationsConfiguration>()); } public DbSet<Member> Members { get; set; } public DbSet<Score> Scores { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); modelBuilder.Entity<Member>().HasMany(b => b.Scores); } } internal sealed class EFDbMigrationsConfiguration : DbMigrationsConfiguration<EFContext> { public EFDbMigrationsConfiguration() { AutomaticMigrationsEnabled = true;//任何Model Class的修改將會自動直接更新DB AutomaticMigrationDataLossAllowed = true; //可接受自動遷移期間的數據丟失的值 } }
2.BaseEntity類
BaseEntity類中定義了所有參加數據操作實體的公共屬性,因此我們把該類定義為抽象類,作為派生類的的基類。
public abstract class BaseEntity { [Key] public Guid Id { get; set; } public DateTime CreateDate { get; set; } public BaseEntity() { Id = Guid.NewGuid(); CreateDate = DateTime.Now; } }
3.Repository模式中最底層的接口實現IRepository
我們對實體的公共操作部分,提取為IRepository接口,比如常見的增加,刪除、修改等方法。
public interface IRepository<TEntity> where TEntity:BaseEntity { DbSet<TEntity> Entities { get; } //增加單個實體 int Insert(TEntity entity); //增加多個實體 int Insert(IEnumerable<TEntity> entities); //更新實體 int Update(TEntity entity); //刪除 int Delete(object id); //根據逐漸獲取實體 TEntity GetByKey(object key); }
其中的接口方法的定義,也會根據具體項目中業務,來進行定義適應自身的方法。具有一定的靈活性
我們發現接口的泛型TEntity有一個約束需要繼承BaseEntity,BaseEntity就是把實體中公共的屬性抽取出來,比如:Id(主鍵),CreateDate(創建時間)等。
4.Repository模式中基於接口的抽象類EFRepositoryBase
我們用一個抽象類EFRepositoryBase來實現接口中的方法,這樣派生的類都具有接口中定義的方法,也防止EFRepositoryBase直接被實例化。
public abstract class EFRepositoryBase<TEntity>:IRepository<TEntity> where TEntity:BaseEntity { EFContext EF = new EFContext(); public DbSet<TEntity> Entities { get { return EF.Set<TEntity>(); } } public int Insert(TEntity entity) { Entities.Add(entity); return EF.SaveChanges(); } public int Insert(IEnumerable<TEntity> entities) { Entities.AddRange(entities); return EF.SaveChanges(); } public int Update(TEntity entity) { EF.Entry(entity).State = EntityState.Modified; return EF.SaveChanges(); } public int Delete(object id) { ///刪除操作實現 return 0; } public TEntity GetByKey(object key) { return Entities.Find(key); } }
5.簡單調用
可以看到就這樣即可進行調用處理。
總結
簡單的項目分層,這里只是簡單的處理分層,並沒有真正意義上的。僅供參考。
簡單測試項目下載鏈接地址