文档章节

[开源]Entity Framework 6 Repository 一种实现方式

o
 osc_gu9d45li
发布于 2019/04/09 19:35
字数 1792
阅读 26
收藏 0

精选30+云产品,助力企业轻松上云!>>>

  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. 欢迎Star,欢迎Issues;

插播一条求职

  1. 小弟拥有多年C#开发经验,从事过路灯,消防平台物联网平台开发,坐标上海;
  2. 如果贵司在招聘,烦请大佬考虑下,联系邮箱:MeetYan@outlook.com

标准仓储

/// <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. 小弟不才,大佬轻拍;
o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
[开源]Dapper Repository 一种实现方式

接着上篇[开源]Entity Framework 6 Repository 一种实现方式 由于Dapper 本身就是轻量级Orm特性,这里参考Creating a Data Repository using Dapper dynamic queries in dapper 代码,来解决...

osc_gni094m4
2019/04/10
1
0
目前的.NET(C#)世界里,主流的ORM框架

推荐一些常用的asp.net ORM框架 SqlSugar (国内) Dos.ORM (国内) Chloe (国内) StackExchange/Dapper (国外) Entity Framework (EF) (国外) NHibernate (国外) ServiceStack/ServiceStack.O......

osc_lteogyh9
2018/08/22
2
0
[开源]MasterChief 快速开发辅助类库

C# 开发辅助类库,和士官长一样身经百战且越战越勇的战争机器,能力无人能出其右。GitHub:MasterChief 欢迎Star,欢迎Issues;项目架构思维导图: 目录 1. 数据库访问 2. 日志 3. 缓存 4. 配...

osc_ertc0ko2
04/16
1
0
推荐博客文章

这里是一些个人感觉本博客里比较值得一看的文章。 开发和常用工具推荐清单 .Net基础 枚举类型转换成字符串 Math.Round和四舍五入 关于DateTime和String转换的容易犯得错误 C#只允许运行应用程...

JustRun
2013/04/09
0
0
.NET(C#)主流的ORM框架

.NET(C#)主流ORM总揽 SqlSugar (国内) Dos.ORM (国内) Chloe (国内) StackExchange/Dapper (国外) Entity Framework (EF) (国外) NHibernate (国外) ServiceStack/ServiceStack.OrmLite (国外......

hofmann
2018/05/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

63. Unique Paths II

题目: 63. Unique Paths II A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The robot can only move either down or right at any p......

JiaMing
49分钟前
30
0
前后端分离了,跨域问题怎么处理?

利用Nginx反向代理解决跨域问题 使用jsonp 来进行解决,不推荐,老项目可以使用此方案,但是发送的http 请求体有大小限制,并且发送方式为get方式,大小限制、不安全。 服务器代理 CORS 请求...

SpringForA
51分钟前
19
0
Hacker News 简讯 2020-07-10

更新时间: 2020-07-10 01:02 Slate Star Codex and Silicon Valley’s War Against the Media - (newyorker.com) 《板岩之星》与硅谷对媒体的战争 得分:102 | 评论:42 US Supreme Court deem......

FalconChen
今天
109
2
如何在Java中将文本追加到现有文件 - How to append text to an existing file in Java

问题: I need to append text repeatedly to an existing file in Java. 我需要将文本重复添加到Java中的现有文件中。 How do I do that? 我怎么做? 解决方案: 参考一: https://stackoom...

fyin1314
昨天
12
0
Eclipse HotKey:如何在选项卡之间切换? - Eclipse HotKey: how to switch between tabs?

问题: How can I switch between opened windows in Eclipse? 如何在Eclipse中打开的窗口之间切换? There is Ctrl + F6 , but it's asking me which one I want, but I want switch it lik......

富含淀粉
昨天
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部