原文:Entity Framework Repository模式
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.简单调用
可以看到就这样即可进行调用处理。
总结
简单的项目分层,这里只是简单的处理分层,并没有真正意义上的。仅供参考。
简单测试项目下载链接地址