1. 程式人生 > >分享基於Entity Framework的Repository模式設計(附原始碼)

分享基於Entity Framework的Repository模式設計(附原始碼)

這篇文章介紹的是使用Entity Framework實現的Repositoy模式設計,歡迎各位拍磚.

閱讀目錄:

一、實現的思路和結構圖

二、Repository設計具體的實現程式碼

三、Repository設計的具體的使用

四、總結

一,實現的思路和結構圖

總結一下,Repository在實際使用中,有下面三種特點:

Repository的共同性

有一些公共的方法(增刪改查), 這些方法無關於Repository操作的是哪個實體類,可以把這些方法定義成介面IRepository<TEntity>, 然後有個基類BaseRepository<TEntity>實現該介面的方法。

常見的方法,比如Find, Filter, Delete, Create等

Repository的差異性

每個Repository類又會有一些差異性,應當允許它們能夠繼承BaseRepository<TEntity>之外,還能夠再擴充套件自己的一些方法。所以每個類都可以再定義一個自己特有的介面,定義一些屬於自己Repository的方法。

Repository的協同性

不同的Repository可能需要協同,Repository對資料的修改,需要在統一的儲存.

最終實現的類結構圖如下:

二,Repository設計具體的實現程式碼

IRepository<TEntity>介面定義了Repository共有的方法, BaseRepository<TEntity>實現了這些介面的方法。其它的Repository類再整合BaseRepository<TEntity>方法,就天然的得到了對資料操作的基本方法。

IRepository<TEntity>程式碼

public interface IRepository<TEntity> where TEntity : class
{
      IQueryable<TEntity> All();
      IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> predicate);
      IQueryable<TEntity> Filter(Expression<Func<TEntity, bool
>> filter, out int total, int index = 0, int size = 50); bool Contains(Expression<Func<TEntity, bool>> predicate); TEntity Find(params object[] keys); TEntity Find(Expression<Func<TEntity, bool>> predicate); TEntity Create(TEntity t); void Delete(TEntity t); void Delete(Expression<Func<TEntity, bool>> predicate); void Update(TEntity t); TEntity Single(Expression<Func<TEntity, bool>> expression); }

BaseRepository<TEntity>程式碼

 public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected readonly DbContext Context;

        public BaseRepository(DbContext context)
        {
            Context = context;
        }

        public TEntity FirstOrDefault(Expression<Func<TEntity, bool>> expression)
        {
            return All().FirstOrDefault(expression);
        }

        public IQueryable<TEntity> All()
        {
            return Context.Set<TEntity>().AsQueryable();
        }

        public virtual IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> predicate)
        {
            return Context.Set<TEntity>().Where<TEntity>(predicate).AsQueryable<TEntity>();
        }

        public virtual IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> filter, out int total, int index = 0,
                                               int size = 50)
        {
            var skipCount = index * size;
            var resetSet = filter != null
                                ? Context.Set<TEntity>().Where<TEntity>(filter).AsQueryable()
                                : Context.Set<TEntity>().AsQueryable();
            resetSet = skipCount == 0 ? resetSet.Take(size) : resetSet.Skip(skipCount).Take(size);
            total = resetSet.Count();
            return resetSet.AsQueryable();
        }

        public virtual void Create(TEntity TObject)
        {
            Context.Set<TEntity>().Add(TObject);
        }

        public virtual void Delete(TEntity TObject)
        {
            Context.Set<TEntity>().Remove(TObject);
        }

        public virtual void Update(TEntity TObject)
        {
            try
            {
                var entry = Context.Entry(TObject);
                Context.Set<TEntity>().Attach(TObject);
                entry.State = EntityState.Modified;
            }
            catch (OptimisticConcurrencyException ex)
            {
                throw ex;
            }
        }

        public virtual int Delete(Expression<Func<TEntity, bool>> predicate)
        {
            var objects = Filter(predicate);
            foreach (var obj in objects)
                Context.Set<TEntity>().Remove(obj);
            return Context.SaveChanges();
        }

        public bool Contains(Expression<Func<TEntity, bool>> predicate)
        {
            return Context.Set<TEntity>().Any(predicate);
        }

        public virtual TEntity Find(params object[] keys)
        {
            return Context.Set<TEntity>().Find(keys);
        }

        public virtual TEntity Find(Expression<Func<TEntity, bool>> predicate)
        {
            return Context.Set<TEntity>().FirstOrDefault<TEntity>(predicate);
        }
    }
View Code

IUnitOfWork介面定義了方法獲取特定的Repository, 執行儲存過程, SaveChange方法提交修改,統一更新資料。

IUnitOfWork介面程式碼:

public interface IUnitOfWork : IDisposable
{
      TRepository GetRepository<TRepository>() where TRepository : class;
      void ExecuteProcedure(string procedureCommand, params object[] sqlParams);
      void SaveChanges();
}

UnitOfWork程式碼, 程式碼中使用到了Autofac中的IComponentContext來獲取Repository例項

public class UnitOfWork : IUnitOfWork
{
       private readonly IComponentContext _componentContext;
       protected readonly DbContext Context;

       public UnitOfWorkRepository(DbContext context, IComponentContext componentContext)
       {
           Context = context;
           _componentContext = componentContext;
       }

       public TRepository GetRepository<TRepository>() where TRepository : class
       {
           return _componentContext.Resolve<TRepository>();
       }

       public void ExecuteProcedure(string procedureCommand, params object[] sqlParams)
       {
           Context.Database.ExecuteSqlCommand(procedureCommand, sqlParams);
       }

       public void SaveChanges()
       {
           Context.SaveChanges();
       }

       public void Dispose()
       {
           if (Context != null)
               Context.Dispose();
       }
}

三, Repository設計的具體的使用

這裡我們定義一個操作Student的Repository類,看看如何實際用於開發中。這裡加入StudentRepository有自己特定的方法,需要獲取所有的Students,這個擴充套件的方法名字叫GetAllStudents

那麼定義一個介面IStudentRepository, 包含了方法GetAllStudents(), 同時繼承IRepository<Student>介面

public interface IStudentRepository : IRepository<Student>
{
      IEnumerable<dynamic> GetAllStudents();
}

然後定義StudentRepository類來實現這個介面

public class StudentRepository : BaseRepository<Student>, IStudentRepository
{
       private readonly SchoolContext _context;

       public StudentRepository(SchoolContext context)
           : base(context)
       {
           _context = context;
       }

       public IEnumerable<dynamic> GetAllStudents()
       {
           return _context.Students;
       }
}

使用Repository的程式碼如下:

IUnitOfWork unitOfWork = new UnitOfWork();

var studentRepository = unitOfWork.GetRepository<IStudentRepository>();
var students = studentRepository.GetAllStudents();

//同時你也可以使用定義於IRepository<Student>中的方法, 比如
//unitOfWork.Delete(students.First());
//unitOfWork.SaveChanges();

四,總結

上面的設計,把Repository的通用程式碼剝離到父類中,同時又允許每個Repository擴充套件自己的方法,達到了比較理想的狀態。

只是現在的設計和Autofac耦合了,但是想剝離Autofac的話,直接使用下面的方式獲取IStudentRepository的例項就很困難。

unitOfWorkRepository.GetRepository<IStudentRepository>();

如果有什麼好的辦法,歡迎指教。也歡迎各位拍磚。

最後,附上本文的相關原始碼. RepositoryDesign.zip有朋友反映這個設計有問題,希望大家批判的看待。如果有不同看法,歡迎指教。

五, 反饋及更新

感謝熱心的園友提供的意見。 這個Repository的設計是不成熟的,在使用了一段EF和看了一些文章之後,自己的一些探索和思考,還沒有應用到實際專案中。

提到的Single方法不合適,已經改成FirstOrDefault()

相關推薦

分享基於Entity Framework的Repository模式設計原始碼

這篇文章介紹的是使用Entity Framework實現的Repositoy模式設計,歡迎各位拍磚. 閱讀目錄: 一、實現的思路和結構圖 二、Repository設計具體的實現程式碼 三、Repository設計的具體的使用 四、總結 一,實現的思路和結構圖 總結一下,Reposit

機器學習專案的例項分析設計原始碼

摘要說明: 最近在學習“Hands-On Machine Learning with Scikit-Learn &TensorFlow”,其中一些機器學習的思考和處理方式很具有專案級開發的特點。我在原文提供的例項基礎上,結合自己的分析,模擬了一個機器學習專案的分析和實現過程,包括專

面向物件以及運用最大最小搜尋的井字棋設計原始碼

一:實驗題目 井字棋遊戲設計 利用面向物件程式設計的知識,通過設計board、player、game類,實現一個具有人人對弈、人機對弈以及機機對弈的井字棋遊戲。 要求: ①對類設定和實現的要求 1.封裝:需要對遊戲中的資料進行相應的封裝保護。 在井字

C#設計模式02-抽象工廠模式原始碼

        抽象工廠模式是所有工廠模式中最為抽象的模式,是抽象程度最高的模式,也是最難理解的一種工廠模式。         現在舉一個生活中的案例來

分享分享一個基於SSH實現的簡單學生選課系統原始碼

歡迎關注微信賬號:java那些事:csh624366188.每天一篇java相關的文章 java交流工作群1: 77800592(已滿) java交流學生群2:234897635(已滿) java交流工作群3:94507287 java交流工作群4: 272265434 我的郵箱:

快過年了,Python大神給免費分享一個爬取12306火車票例子原始碼

。。。 上面是以前寫的文章的資源,在以前的文章中有對應的資源,有興趣的可以去檢視。 作為一種便捷地收集網上資訊並從中抽取出可用資訊的方式,網路爬蟲技術變得越來越有用。使用Python這樣的簡單程式語言,你可以使用少量程式設計技能就可以爬取複雜的網站。 如果手機上顯示程式碼錯亂,請分

Activity生命週期互動設計思想和應用場景原始碼

Activity生命週期互動設計思想 1.在多個Activity進行互動的時候,為什麼要先暫停(onPause()方法)當前的Activity,執行新的Activity的onCreate()方法,onStart()方法,onResume()方法? 答:比

分享十道Selenium面試題答案

軟體測試培訓也是一種提升技術及迅速轉行的輔助手段,不管在哪學你都必須先去試聽,看看講課的風格及氛圍,是否通俗易懂,課件是否老化,工具是否過時,課程內容及專案是否具有實戰性,主要就是了解專案實戰週期是多久,工具是否屬現在主流,還有你自己喜不喜歡講師的講課風格,如果不喜歡講師

漢諾塔遊戲的設計程式碼

漢諾塔遊戲的設計 漢諾塔問題是最經典的遞迴問題,筆者就該問題設計了這個遊戲,由使用者互動遊戲和自動演示兩部分組成,支援撤銷功能、選關、自動完成等功能。   首先建立了類CMap,該類主要實現使用者每一步的操作和畫圖顯示功能,記錄的時候只須記錄每組盤子的個數和盤子的矩形。程

STM32CubeMX的SDIO模式下對SD卡讀寫測試原始碼

1.問題描述:使用STM32CubeMX,配置SDIO的4bit模式,對SD卡進行讀寫測試。 2.準備工作: 軟體版本:STM32CubeMX–4.22.0 ;KEIL5 硬體平臺:原子戰艦V3 (1)軟體設定: I. SDIO選擇,這裡選擇4

Linux下基於UDP協議實現的聊天室專案原始碼

好久沒來更新了,這段時間一直在著手完成這個專案,由於之前沒有接觸過這種稍大型的專案,而且對於C/S架構以及UDP通訊的瞭解也不是很深,所以前面很大的一段時間都被浪費掉了,做了很大無用功。 剛開始弄的時候,也是在網上搜了很多資料,找了很多版本,發現大都有

基於Web日誌挖掘的個性化推薦系統原始碼

個性化推薦系統 實現該系統主要是使用的程式語言主要是R,然後配合css在樣式上進行一定優化,使用shiny開發的一款web程式,主要實現的核心功能是基於spark的ALS演算法的課程個性化推薦系統。首頁介面如下圖所示: 該系統中的所有課程名稱,課程圖片以及課程連結均從

基於springBoot實現給圖片新增文字水印原始碼

原始碼在最下面 程式背景 在網路中的很多地方都有水印的存在,比如微信公眾號上面的圖片,微博 等……所以老闆也要求我們在圖片上傳時新增自己的水印。 所以寫了一個工具類。

Spring整合JMS——基於ActiveMQ實現原始碼

宣告:本文轉載地址:http://elim.iteye.com/blog/1893038,如不能轉載,請聯絡博主。 此原始碼非彼原始碼,如需下載原文原始碼,請訪問原文連結。 此原始碼是博主經過改造測試的,可以配合此文章閱讀。地址:去下載 JMS簡介

基於stm32的自定義HID裝置開發與上位機通訊實現原始碼

現在主流的安卓手機資料連線線,Mini-usb、Micro-usb,Type-c,產品追隨主流,非聯網裝置,摒棄ST-LINK、JLINK,直接用usb資料傳輸升級。主要實現與HID裝置的通訊即人機互動。本文主要介紹了HID裝置的下位機通訊連線與上位機裝置識別。 下位機:

基於C#的內網穿透學習筆記原始碼

如何讓兩臺處在不同內網的主機直接互連?你需要內網穿透!          上圖是一個非完整版內外網通訊圖由內網端先發起,內網裝置192.168.1.2:6677傳送資料到外網時候必須經過nat會轉換成對應的外網ip+埠,然後在傳送給外網裝置,

mysql 使用 limit 實現底層分頁原始碼

原理解析: <select id="queryProductList" resultType="com.pojo.Product"> SELECT * FROM tb_product ORDER BY priority DESC LIMIT #{rowIndex},#{p

使用高德地圖微信小程式SDK開發案例-輸入提示原始碼

閒來無事寫一篇使用高德地圖的微信小程式SDK開發應用的例項。 接下來先看需求: 我們要做的是,根據使用者輸入的關鍵詞,給出相應的提示資訊,列表中顯示地方的名稱,地方的詳細地址以及對應的經緯度座標。 當然在UI上我們儘量做到理想的視覺與較好的使用者體驗。 最終的效果我們希望是像這樣的,

乾貨原始碼 | 爬取一萬條b站評論,分析9.7分的新番憑啥這麼火?

7月番《工作細胞》最終話在十一前放出。這部動漫在b站上評分高達9.7。除了口碑之外,熱度也居高不下,更值得關注的是連很多平時不關注動漫的小夥伴也加入了追番大軍。這次我們的目標是爬取b站上的所有短評進行分析,用資料說明為什麼這部動漫會如此受歡迎。 01 工作細胞 《工作細胞》

CVPR論文《100+ Times FasterWeighted Median Filter (WMF)》的實現和解析(附原始碼)。 任意半徑中值濾波擴充套件至百分比濾波器O(1)時間複雜度演算法的原理、實現及效果 任意半徑中值濾波擴充套件至百分比濾波器O(1)時間複雜度演算法的原理、實現及

  四年前第一次看到《100+ Times FasterWeighted Median Filter (WMF)》一文時,因為他附帶了原始碼,而且還是CVPR論文,因此,當時也對程式碼進行了一定的整理和解讀,但是當時覺得這個演算法雖然對原始速度有不少的提高,但是還是比較慢。因此,沒有怎麼在意,這幾天有幾位朋友