[开源]Entity Framework 6 Repository 一种实现方式
- 在使用Entity Framework这种ORM框架得时候,一般结合Repository仓储形式来处理业务逻辑;虽然这种模式带来很多好处,但是也会引发一些争议,在此抛开不谈,小弟结合项目经验来实现一下,欢迎大佬拍砖;
- 后续会带来Dapper 基于Repository实现,代码一些实现会兼容Dapper,所以做了一些比较丑陋得写法;但是我得想法是通过一些Ioc可以在Entity Framework和Dapper两者之间进行切换;
- 您可以通过Nuget:Install-Package MasterChief.DotNet.Core.EF 安装使用;
- 您可以通过Github:MasterChief 查看具体源码以及单元测试
- 欢迎Star,欢迎Issues;
插播一条求职
- 小弟拥有多年C#开发经验,从事过路灯,消防平台物联网平台开发,坐标上海;
- 如果贵司在招聘,烦请大佬考虑下,联系邮箱: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);
}
}
结语
- 通过上述代码,可以在项目中很方面使用Entity Framework;
- 并且很轻松实现CURD以及事务处理,从而开发中关注业务即可;
- 小弟不才,大佬轻拍;
[开源]Entity Framework 6 Repository 一种实现方式的更多相关文章
- [开源]Dapper Repository 一种实现方式
接着上篇[开源]Entity Framework 6 Repository 一种实现方式 由于Dapper 本身就是轻量级Orm特性,这里参考Creating a Data Repository us ...
- Entity Framework中的几种加载方式
在Entity Framework中有三种加载的方式,分别是延迟加载,自动加载和显示加载.下面用一个例子来说明:现在有两个表,一个是资料表(Reference),另外一个表是资料分类表 ...
- 分享基于Entity Framework的Repository模式设计(附源码)
关于Repository模式,在这篇文章中有介绍,Entity Framework返回IEnumerable还是IQueryable? 这篇文章介绍的是使用Entity Framework实现的Rep ...
- 关于Entity Framework更新的几种方式以及可能遇到的问题(附加类型“Model”的实体失败,因为相同类型的其他实体已具有相同的主键值)在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 时如果图形中的任何实体具有冲突键值,则可能会发生上述行为
在日常使用Entity Framework中,数据更新通常会用到.下面就简单封装了一个DBContext类 public partial class EFContext<T> : DbCo ...
- Entity Framework 数据库初始化四种策略
策略一:数据库不存在时重新创建数据库 Database.SetInitializer<testContext>(new CreateDatabaseIfNotExists<testC ...
- Entity Framework数据库初始化四种策略
策略一:数据库不存在时重新创建数据库 程序代码 Database.SetInitializer<testContext>(new CreateDatabaseIfNotExists< ...
- 浅谈Entity Framework中的数据加载方式
如果你还没有接触过或者根本不了解什么是Entity Framework,那么请看这里http://www.entityframeworktutorial.net/EntityFramework-Arc ...
- Entity Farmework领域建模方式 3种编程方式
一个业务领域由各个实体和各个相互关联且有格子的属性和行为的实体组成,每个实体都有其状态和验证规则需要维护,Entity Framework (后面简称EF)实体框架设计的出现是为了允许开发人员着重关注 ...
- Entity FrameWork初始化数据库的四种策略
程序猿就是苦逼,每天还得分出一些时间去写博文.天真的很热,今天就随便写一点啦! 1.EF初始化数据库的四中策略 EF可以根据项目中的模型自动创建数据库.下面我们就分类看看Entity Framewor ...
随机推荐
- stm.go
package) ].ModRevision } func,, ,, ].ModRevision ].Value) }
- [Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086
额... 首先,看到这道题,第一想法就是二分答案+线段树... 兴高采烈的认为我一定能AC,之后发现n是500000... nlog^2=80%,亲测可过... 由于答案是求满足题意的最大长度-最小长 ...
- linux文件的基本属性
Linux 文件基本属性 Linux系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限.为了保护系统的安全性,Linux系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规 ...
- 在CentOS 7中启动/停止/重启服务
RHEL/CentOS 7.0中一个最主要的改变,就是切换到了systemd.它用于替代红帽企业版Linux前任版本中的SysV和Upstart,对系统和服务进行管理.systemd兼容SysV和Li ...
- Go语言中的面向对象
前言 如果说最纯粹的面向对象语言,我觉得是Java无疑.而且Java语言的面向对象也是很直观,很容易理解的.class是基础,其他都是要写在class里的. 最近学习了Go语言,有了一些对比和思考.虽 ...
- Docker最全教程——Redis容器化以及排行榜实战(十三)
前言 容器教程的路还很长,笔者尽量根据实践来不断地完善.由于在编写的过程中还会有完善和补充,后续可能会以番外来补充. 接下来会分享TeamCity.树莓派等内容,节奏可能会有点跳脱. 另外,长沙.NE ...
- 浏览器加载 CommonJS 模块的原理与实现
就在这个周末,npm 超过了 cpan ,成为地球上最大的软件模块仓库. npm 的模块都是 JavaScript 语言写的,但浏览器用不了,因为不支持 CommonJS 格式.要想让浏览器用上这些模 ...
- 【Android Studio安装部署系列】目录
概述 从刚开始使用Android Studio到现在,下面所有目录下的操作,当时习惯性的把每一个整理成一个文档(其实就是简单文字描述+截图):有些地方当时是一知半解,现在会稍微明白一些.正好赶上现在有 ...
- 面试前必须要知道的Redis面试题
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 回顾前面: 从零单排学Redis[青铜] 从零单排学 ...
- C# 23种设计模式
目录 0).简单工厂模式 1).工厂方法模式 2).抽象工厂模式 3).单例模式 4).构建者模式 5).原型模式 6).适配器模式 7).修饰者模式 8).代理模式 9).外观模式 10).桥接模式 ...