數據訪問層無非就是對數據進行增刪改查,其中增、刪、改等我們可以抽象出來寫一個公共的接口或抽象類來定義這些方法,並采用一個基類實現這些方法,這樣該基類派生的子類都會繼承增、刪、改這些方法,這樣我們就避免了每個實體都要重復實現這些方法。一句話概括就是:通過接口 泛型 與ORM結合 實現了數據訪問層更好的復用。
在《企業架構模式》中,譯者將Repository翻譯為資源庫。給出如下說明:通過用來訪問領域對象的一個類似集合的接口,在領域與數據映射層之間進行協調。
下面我們就用EF來實現一個簡單的Repository模式
1、我們對實體的公共操作部分,提取為IRepository接口,比如常見的增加,刪除、修改等方法。如下代碼
我們發現接口的泛型TEntity有一個約束需要繼承BaseEntity,BaseEntity就是把實體中公共的屬性抽取出來,比如:Id(主鍵),CreateDate(創建時間)等。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Repository.Model; using System.Data.Entity; namespace Repository.Data { 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); } }
2、BaseEntity類
BaseEntity類中定義了所有參加數據操作實體的公共屬性,因此我們把該類定義為抽象類,作為派生類的的基類。代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.DataAnnotations; namespace Repository.Model { public abstract class BaseEntity { public BaseEntity() { Id = Guid.NewGuid(); CreateDate = DateTime.Now; } [Key] public Guid Id { get; set; } public DateTime CreateDate { get; set; } } }
3、IRepository接口定義完畢,肯定需要一個雷來實現接口中的方法,下面我們定義一個抽象類EFRepositoryBase來實現該接口方法
我們用一個抽象類EFRepositoryBase來實現接口中的方法,這樣派生的類都具有接口中定義的方法,也防止EFRepositoryBase直接被實例化,下面我們直接看代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Repository.Model; using System.Data.Entity; namespace Repository.Data { public abstract class EFRepositoryBase<TEntity> : IRepository<TEntity> where TEntity:BaseEntity { DemoDbContext Db = new DemoDbContext(); #region IRepository<TEntity> 成員 public DbSet<TEntity> Entities { get { return Db.Set<TEntity>(); } } public int Insert(TEntity entity) { Db.Set<TEntity>().Add(entity); return Db.SaveChanges(); } public int Insert(IEnumerable<TEntity> entities) { throw new NotImplementedException(); } public int Update(TEntity entity) { return 0; } public int Delete(object id) { throw new NotImplementedException(); } public TEntity GetByKey(object key) { return Db.Set<TEntity>().Find(key); } #endregion } }
因為我們用的EF作為數據訪問,因此我們需要定義一個數據上下文,代碼如下

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; using Repository.Model; using System.Data.Entity.Migrations; using System.Data.Entity.ModelConfiguration.Conventions; namespace Repository.Data { public class DemoDbContext : DbContext { public DemoDbContext() : base("default") { Database.SetInitializer<DemoDbContext>(new MigrateDatabaseToLatestVersion<DemoDbContext, ReportingDbMigrationsConfiguration>()); } 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 ReportingDbMigrationsConfiguration : DbMigrationsConfiguration<DemoDbContext> { public ReportingDbMigrationsConfiguration() { AutomaticMigrationsEnabled = true;//任何Model Class的修改將會直接更新DB AutomaticMigrationDataLossAllowed = true; } } }

<connectionStrings> <add name="default" connectionString="Data Source=ERIC\SQLEXPRESS;Initial Catalog=EfSample;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings>
我們一共定義兩個實體,一個是Members(學生)類和Scores(成績)類,Members與Scores為一對多的關系。
4、Members類和Scores類,都要繼承BaseEntity基類

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.DataAnnotations.Schema; namespace Repository.Model { [Table("tb_Member",Schema="dbo")] public class Member:BaseEntity { public int Num { get; set; } public string UserName { get; set; } public string Sex { get; set; } public int Age { get; set; } [ForeignKey("MemberId")] public virtual ICollection<Score> Scores { get; set; } } }

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.DataAnnotations.Schema; namespace Repository.Model { [Table("tb_Score",Schema="dbo")] public class Score:BaseEntity { public Guid MemberId { get; set; } public double Scores { get; set; } public Guid courseId { get; set; } } }
基礎工作都已經完成了,下面我們來看 MemberRepository.cs類和ScoreRespository.cs類。
所有的數據操作都在EFRepositoryBase.cs中實現了,因此MemberRepository.cs和ScoreRespository.cs只需要繼承EFRepositoryBase,即可實現增刪改查。
1、MemberRepository.cs
MemberRepository為實體Member的操作類,因此EFRepositoryBase基類中的泛型被替換成實體Member,這樣該類中就已經有了對Member的增刪改查操作,我們也可以在MemberRepository中定義其他方法。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Repository.Model; namespace Repository.Data { public class MemberRepository : EFRepositoryBase<Member>, IRepository<Member> { } }
2、ScoreRespository.cs
ScoreRespository與MemberRepository一樣,只不過是對實體Score的操作。
3、簡單測試
public void test() { MemberRepository mr = new MemberRepository(); var entity = new Member() { UserName = "eric", Age = 25, Sex = "男" }; mr.Insert(entity); var score = new Score() { MemberId = entity.Id, Scores = 80, courseId = Guid.NewGuid() }; ScoreRespository sr = new ScoreRespository(); sr.Insert(score); }
我們發現數據操作成功。
一般Repository都會跟Unit of Work模式聯合使用,如果你有好的學習資料歡迎分享,Unit of Work模式曾看了一天也沒有理解其精髓。
每天學習一點點,每天進步一點點。