[開源]Entity Framework 6 Repository 一種實現方式

来源:https://www.cnblogs.com/MeetYan/archive/2019/04/09/10679158.html
-Advertisement-
Play Games

1. 在使用Entity Framework這種ORM框架得時候,一般結合Repository倉儲形式來處理業務邏輯;雖然這種模式帶來很多好處,但是也會引發一些爭議,在此拋開不談,小弟結合項目經驗來實現一下,歡迎大佬拍磚; 2. 後續會帶來Dapper 基於Repository實現,代碼一些實現會兼 ...


  1. 在使用Entity Framework這種ORM框架得時候,一般結合Repository倉儲形式來處理業務邏輯;雖然這種模式帶來很多好處,但是也會引發一些爭議,在此拋開不談,小弟結合項目經驗來實現一下,歡迎大佬拍磚;
  2. 後續會帶來Dapper 基於Repository實現,代碼一些實現會相容Dapper,所以做了一些比較醜陋得寫法;但是我得想法是通過一些Ioc可以在Entity Framework和Dapper兩者之間進行切換;
  3. 您可以通過Nuget:Install-Package MasterChief.DotNet.Core.EF 安裝使用;
  4. 您可以通過Github:MasterChief 查看具體源碼以及單元測試
  5. 歡迎PR,歡迎Star;

插播一條求職

  1. 小弟擁有多年C#開發經驗,從事過路燈,消防平臺物聯網平臺開發,坐標上海;
  2. 如果貴司在招聘,煩請大佬考慮下,聯繫郵箱:[email protected]

標準倉儲

/// <summary>
/// 標準倉儲介面
/// </summary>
public interface IRepository
{
    #region Methods
 
    /// <summary>
    /// 刪除記錄
    /// </summary>
    /// <returns>操作是否成功</returns>
    /// <param name="entity">需要操作的實體類.</param>
    bool Delete<T>(T entity) where T : ModelBase;
 
    /// <summary>
    /// 條件判斷是否存在
    /// </summary>
    /// <returns>是否存在</returns>
    /// <param name="predicate">判斷條件委托</param>
    bool Exist<T>(Expression<Func<T, bool>> predicate = null) where T : ModelBase;
 
    /// <summary>
    /// 根據id獲取記錄
    /// </summary>
    /// <returns>記錄</returns>
    /// <param name="id">id.</param>
    T GetByKeyId<T>(object id) where T : ModelBase;
 
    /// <summary>
    /// 條件獲取記錄集合
    /// </summary>
    /// <returns>集合</returns>
    /// <param name="predicate">篩選條件.</param>
    List<T> GetList<T>(Expression<Func<T, bool>> predicate = null) where T : ModelBase;
 
    /// <summary>
    /// 條件獲取記錄第一條或者預設
    /// </summary>
    /// <returns>記錄</returns>
    /// <param name="predicate">篩選條件.</param>
    T GetFirstOrDefault<T>(Expression<Func<T, bool>> predicate = null) where T : ModelBase;
 
    /// <summary>
    /// 創建一條記錄
    /// </summary>
    /// <returns>操作是否成功.</returns>
    /// <param name="entity">實體類記錄.</param>
    bool Create<T>(T entity) where T : ModelBase;
 
    /// <summary>
    /// 條件查詢
    /// </summary>
    /// <returns>IQueryable</returns>
    /// <param name="predicate">篩選條件.</param>
    IQueryable<T> Query<T>(Expression<Func<T, bool>> predicate = null) where T : ModelBase;
 
    /// <summary>
    /// 根據記錄
    /// </summary>
    /// <returns>操作是否成功.</returns>
    /// <param name="entity">實體類記錄.</param>
    bool Update<T>(T entity) where T : ModelBase;
 
    #endregion Methods
}

數據訪問上下文介面

public interface IDbContext : IDisposable, IRepository, IUnitOfWork
{
    /// <summary>
    ///     執行Sql 腳本查詢
    /// </summary>
    /// <param name="sql">Sql語句</param>
    /// <param name="parameters">參數</param>
    /// <returns>集合</returns>
    IEnumerable<T> SqlQuery<T>(string sql, IDbDataParameter[] parameters);
}

數據訪問上下文工廠

public interface IDatabaseContextFactory
{
    /// <summary>
    ///     Create this instance.
    /// </summary>
    /// <returns>The create.</returns>
    IDbContext Create();
}

基於EF的DbContext

public abstract class EfDbContextBase : DbContext, IDbContext
{
    #region Constructors
 
    /// <summary>
    ///     構造函數
    /// </summary>
    /// <param name="dbConnection">dbConnection</param>
    protected EfDbContextBase(DbConnection dbConnection)
        : base(dbConnection, true)
    {
        Configuration.LazyLoadingEnabled = false; //將不會查詢到從表的數據,只會執行一次查詢,可以使用 Inculde 進行手動載入;
        Configuration.ProxyCreationEnabled = false;
        Configuration.AutoDetectChangesEnabled = false;
    }
 
    #endregion Constructors
 
    #region Fields
 
    /// <summary>
    ///     獲取 是否開啟事務提交
    /// </summary>
    public virtual bool TransactionEnabled => Database.CurrentTransaction != null;
 
    #endregion Fields
 
    #region Methods
 
    /// <summary>
    ///     顯式開啟數據上下文事務
    /// </summary>
    /// <param name="isolationLevel">指定連接的事務鎖定行為</param>
    public void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified)
    {
        if (!TransactionEnabled) Database.BeginTransaction(isolationLevel);
    }
 
    /// <summary>
    ///     提交當前上下文的事務更改
    /// </summary>
    /// <exception cref="DataAccessException">提交數據更新時發生異常:" + msg</exception>
    public void Commit()
    {
        if (TransactionEnabled)
            try
            {
                Database.CurrentTransaction.Commit();
            }
            catch (DbUpdateException ex)
            {
                if (ex.InnerException?.InnerException is SqlException sqlEx)
                {
                    var msg = DataBaseHelper.GetSqlExceptionMessage(sqlEx.Number);
                    throw new DataAccessException("提交數據更新時發生異常:" + msg, sqlEx);
                }
 
                throw;
            }
    }
 
    /// <summary>
    ///     創建記錄
    /// </summary>
    /// <returns>操作是否成功</returns>
    /// <param name="entity">需要操作的實體類.</param>
    public bool Create<T>(T entity)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(entity, "需要創建數據記錄");
        bool result;
        try
        {
            Entry(entity).State = EntityState.Added;
            result = SaveChanges() > 0;
        }
        catch (DbEntityValidationException dbEx)
        {
            throw new Exception(dbEx.GetFullErrorText(), dbEx);
        }
 
        return result;
    }
 
    /// <summary>
    ///     創建記錄集合
    /// </summary>
    /// <returns>操作是否成功.</returns>
    /// <param name="entities">實體類集合.</param>
    public bool Create<T>(IEnumerable<T> entities)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(entities, "需要創建數據集合");
        bool result;
        try
        {
            foreach (var entity in entities) Entry(entity).State = EntityState.Added;
 
            result = SaveChanges() > 0;
        }
        catch (DbEntityValidationException dbEx)
        {
            throw new Exception(dbEx.GetFullErrorText(), dbEx);
        }
 
        return result;
    }
 
    /// <summary>
    ///     刪除記錄
    /// </summary>
    /// <returns>操作是否成功</returns>
    /// <param name="entity">需要操作的實體類.</param>
    public bool Delete<T>(T entity)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(entity, "需要刪除的數據記錄");
        bool result;
        try
        {
            Entry(entity).State = EntityState.Deleted;
            result = SaveChanges() > 0;
        }
        catch (DbEntityValidationException dbEx)
        {
            throw new Exception(dbEx.GetFullErrorText(), dbEx);
        }
 
        return result;
    }
 
    /// <summary>
    ///     條件判斷是否存在
    /// </summary>
    /// <returns>是否存在</returns>
    /// <param name="predicate">判斷條件委托</param>
    public bool Exist<T>(Expression<Func<T, bool>> predicate = null)
        where T : ModelBase
    {
        return predicate == null ? Set<T>().Any() : Set<T>().Any(predicate);
    }
 
    /// <summary>
    ///     根據id獲取記錄
    /// </summary>
    /// <returns>記錄</returns>
    /// <param name="id">id.</param>
    public T GetByKeyId<T>(object id)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(id, "Id");
        return Set<T>().Find(id);
    }
 
    /// <summary>
    ///     條件獲取記錄集合
    /// </summary>
    /// <returns>集合</returns>
    /// <param name="predicate">篩選條件.</param>
    public List<T> GetList<T>(Expression<Func<T, bool>> predicate = null)
        where T : ModelBase
    {
        IQueryable<T> query = Set<T>();
 
        if (predicate != null) query = query.Where(predicate);
 
        return query.ToList();
    }
 
    /// <summary>
    ///     條件獲取記錄第一條或者預設
    /// </summary>
    /// <returns>記錄</returns>
    /// <param name="predicate">篩選條件.</param>
    public T GetFirstOrDefault<T>(Expression<Func<T, bool>> predicate = null)
        where T : ModelBase
    {
        IQueryable<T> query = Set<T>();
 
        if (predicate != null)
            return query.FirstOrDefault(predicate);
        return query.FirstOrDefault();
    }
 
    /// <summary>
    ///     條件查詢
    /// </summary>
    /// <returns>IQueryable</returns>
    /// <param name="predicate">篩選條件.</param>
    public IQueryable<T> Query<T>(Expression<Func<T, bool>> predicate = null)
        where T : ModelBase
    {
        IQueryable<T> query = Set<T>();
 
        if (predicate != null) query = query.Where(predicate);
 
        return query;
    }
 
    /// <summary>
    ///     顯式回滾事務,僅在顯式開啟事務後有用
    /// </summary>
    public void Rollback()
    {
        if (TransactionEnabled) Database.CurrentTransaction.Rollback();
    }
 
    /// <summary>
    ///     執行Sql 腳本查詢
    /// </summary>
    /// <param name="sql">Sql語句</param>
    /// <param name="parameters">參數</param>
    /// <returns>集合</returns>
    public IEnumerable<T> SqlQuery<T>(string sql, IDbDataParameter[] parameters)
    {
        ValidateOperator.Begin()
            .NotNullOrEmpty(sql, "Sql語句");
        // ReSharper disable once CoVariantArrayConversion
        return Database.SqlQuery<T>(sql, parameters);
    }
 
    /// <summary>
    ///     根據記錄
    /// </summary>
    /// <returns>操作是否成功.</returns>
    /// <param name="entity">實體類記錄.</param>
    public bool Update<T>(T entity)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(entity, "需要更新的數據記錄");
        bool result;
        try
        {
            var set = Set<T>();
            set.Attach(entity);
            Entry(entity).State = EntityState.Modified;
            result = SaveChanges() > 0;
        }
        catch (DbEntityValidationException dbEx)
        {
            throw new Exception(dbEx.GetFullErrorText(), dbEx);
        }
 
        return result;
    }
 
    #endregion Methods
}

單元測試

    [TestClass()]
    public class SampleServiceTests
    {
        private IKernel _kernel;
        private ISampleService _sampleService;
        private readonly Guid _testId = "2F6D3C43-C2C7-4398-AD2B-ED5E82D79999".ToGuidOrDefault(Guid.Empty);
        private const string TestName = "EFSample";
 
        [TestInitialize]
        public void SetUp()
        {
            _kernel = new StandardKernel(new ServiceModule());
            Assert.IsNotNull(_kernel);
 
            _sampleService = _kernel.Get<ISampleService>();
            //if (!_sampleService.Exist(ent => ent.ID == _testID))
            //{
            //    _sampleService.Create(new EFSample() { UserName = _testName, ID = _testID });
            //}
        }
 
        /// <summary>
        /// 創建測試
        /// </summary>
        [TestMethod()]
        public void CreateTest()
        {
            bool actual = _sampleService.Create(new EfSample() { UserName = "ef" + DateTime.Now.ToString("MMddHHmmss") });
            Assert.IsTrue(actual);
 
            actual = _sampleService.Create(new EfSample() { UserName = "ef" + DateTime.Now.ToString("MMddHHmmss") });
            Assert.IsTrue(actual);
 
            actual = _sampleService.Create(new EfSample() { UserName = "ef" + DateTime.Now.ToString("MMddHHmmss") });
            Assert.IsTrue(actual);
 
            actual = _sampleService.Create(new EfSample() { UserName = "ef" + DateTime.Now.ToString("MMddHHmmss") });
            Assert.IsTrue(actual);
 
            actual = _sampleService.Create(new EfSample() { UserName = "ef" + DateTime.Now.ToString("MMddHHmmss") });
            Assert.IsTrue(actual);
        }
 
        [TestMethod()]
        public void GetFirstOrDefaultTest()
        {
            EfSample actual = _sampleService.GetFirstOrDefault(ent => ent.Id == _testId);
            Assert.IsNotNull(actual);
        }
 
        [TestMethod()]
        public void GetByKeyIdTest()
        {
            EfSample actual = _sampleService.GetByKeyId(_testId);
            Assert.IsNotNull(actual);
        }
 
        [TestMethod()]
        public void GetListTest()
        {
            // ReSharper disable once RedundantBoolCompare
            List<EfSample> actual = _sampleService.GetList(ent => ent.Available == true);
            Assert.IsNotNull(actual);
            CollectionAssert.AllItemsAreNotNull(actual);
        }
 
        [TestMethod()]
        public void UpdateTest()
        {
            EfSample sample = new EfSample
            {
                Id = _testId,
                ModifyTime = DateTime.Now,
                UserName = "modify"
            };
            bool actual = _sampleService.Update(sample);
            Assert.IsNotNull(actual);
        }
 
        [TestMethod()]
        public void TransactionSuccessTest()
        {
            EfSample sample = new EfSample
            {
                UserName = "TransactionSuccess1"
            };
 
            EfSample sample2 = new EfSample
            {
                UserName = "TransactionSuccess2"
            };
            bool actual = _sampleService.CreateWithTransaction(sample, sample2);
            Assert.IsTrue(actual);
        }
 
        [TestMethod()]
        public void TransactionFailTest()
        {
            EfSample sample3 = new EfSample
            {
                UserName = "TransactionSuccess3"
            };
 
            EfSample sample4 = new EfSample
            {
                UserName = null
            };
            bool actual = _sampleService.CreateWithTransaction(sample3, sample4);
            Assert.IsFalse(actual);
        }
 
        [TestMethod()]
        public void ExistTest()
        {
            bool actual = _sampleService.Exist(ent => ent.Id == _testId);
            Assert.IsTrue(actual);
 
            actual = _sampleService.Exist(ent => ent.UserName == TestName);
            Assert.IsTrue(actual);
 
            DateTime createTime = DateTime.Now.AddDays(-1);
            actual = _sampleService.Exist(ent => ent.CreateTime >= createTime);
            Assert.IsTrue(actual);
 
            actual = _sampleService.Exist(ent => ent.CreateTime <= DateTime.Now);
            Assert.IsTrue(actual);
 
            // ReSharper disable once RedundantBoolCompare
            actual = _sampleService.Exist(ent => ent.Available == true);
            Assert.IsTrue(actual);
 
            actual = _sampleService.Exist(ent => ent.Available != true);
            Assert.IsFalse(actual);
        }
 
        [TestMethod()]
        public void SqlQueryTest()
        {
            string sql = @"select * from [dbo].[EFSample]
where CreateTime>=@CreateTime
and Available=@Available
order by CreateTime desc";
            DbParameter[] parameter = {
                    new SqlParameter(){ ParameterName="@CreateTime", Value=DateTime.Now.AddDays(-1) },
                    new SqlParameter(){ ParameterName="@Available", Value=true }
                };
            List<EfSample> actual = _sampleService.SqlQuery(sql, parameter);
            Assert.IsNotNull(actual);
            CollectionAssert.AllItemsAreNotNull(actual);
        }
 
        /// <summary>
        /// 多線程測試
        /// </summary>
        [TestMethod()]
        public void CreateTestThreadTest()
        {
            Task[] tasks = {
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                                Task.Factory.StartNew(() => CreateTest()),
                            };
            Task.WaitAll(tasks);
        }
    }

結語

  1. 通過上述代碼,可以在項目中很方面使用Entity Framework;
  2. 並且很輕鬆實現CURD以及事務處理,從而開發中關註業務即可;
  3. 小弟不才,大佬輕拍;

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、類規範 類聲明:包括數據成員、成員函數(共有介面)的聲明 類方法定義 C++程式員將介面(類)放在頭文件中,將實現放在源代碼文件中 類設計儘量將共有介面和實現細節分開,數據隱藏(將數據放在私有部分中)是一種封裝,將實現細節隱藏在私有部分中也是一種封裝。將類函數定義和類聲明放在不同文件中也是一種封 ...
  • this關鍵字: (1)this(當局部變數和成員變數重名時,可以用關鍵字this區分) this代表對象,當前對象 this就是所在函數所屬對象的引用 簡單來說,哪個對象調用了所在的函數,this就代表哪個對象 (2)構造函數調用構造函數,用this調用成員 對this的調用必須是構造函數第一個語 ...
  • 今天清明節假期結束第二天,昨天請了一天假去考科目二,還好考過了,O(∩_∩)O哈哈~~~~ 今天老師講了類的屬性與方法的使用 就用代碼來說明吧: package pkg3;public class Test{ private int a1=0; //這就是聲明屬性a1、a2、a3、、、、 priva ...
  • 上一篇文章,小樂給大家介紹了《Java8新特性之方法引用》,下麵接下來小樂將會給大家介紹Java8新特性之Stream,稱之為流,本篇文章為上半部分。 1、什麼是流? Java Se中對於流的操作有輸入輸出IO流,而Java8中引入的Stream 屬於Java API中的一個新成員,它允許你以聲明性 ...
  • public class 類名{ private double 財產 = 0;//設一個財產的屬性; public void 一個月工資(){ this.財產 +=4500; }//設一個方法增加財產; public double 顯示財產(){ return this.財產; }//設一個方法,返 ...
  • 目前信息化產業發展勢頭很好,互聯網就成為了很多普通人想要涉及的行業,因為相比於傳統行業,互聯網行業漲薪幅度大,機會也多,所以就會大批的人想要轉行來學習Java開發。目前來講市場上需要的Java人員非常多,而且按照現在的勢頭,以後會需要更多的Java開發人員,理由是以後每個人公司都會有自己的網站,有自 ...
  • /// /// 生成隨機的字元串 /// /// 驗證碼長度 /// public string CreateRandomCode(int codeCount) { string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D... ...
  • 晚上利用空閑時間,用Socket做了一些小功能。 功能如下: a.聊天 b.傳文件 c.抖動好友 主界面: 伺服器 客戶端 操作步驟: 伺服器(測試環境的IP地址為:192.168.92.111,視情況而定): >開始監聽 客戶端: >連接 註:服務端和客戶端同時運行步驟: 功能一: 服務端 客戶端 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...