分享基於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論文,因此,當時也對程式碼進行了一定的整理和解讀,但是當時覺得這個演算法雖然對原始速度有不少的提高,但是還是比較慢。因此,沒有怎麼在意,這幾天有幾位朋友