[开源]Entity Framework 6 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. 欢迎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. 小弟不才,大佬轻拍;
posted @ 2019-04-09 19:35 MeetYan 阅读(...) 评论(...) 编辑 收藏