- 在使用Entity Framework这种ORM框架得时候,一般结合Repository仓储形式来处理业务逻辑;虽然这种模式带来很多好处,但是也会引发一些争议,在此抛开不谈,小弟结合项目经验来实现一下,欢迎大佬拍砖;
- 后续会带来Dapper 基于Repository实现,代码一些实现会兼容Dapper,所以做了一些比较丑陋得写法;但是我得想法是通过一些Ioc可以在Entity Framework和Dapper两者之间进行切换;
- 您可以通过Nuget:Install-Package MasterChief.DotNet.Core.EF 安装使用;
- 您可以通过Github:MasterChief 查看具体源码以及单元测试
- 欢迎Star,欢迎Issues;
插播一条求职
- 小弟拥有多年C#开发经验,从事过路灯,消防平台物联网平台开发,坐标上海;
- 如果贵司在招聘,烦请大佬考虑下,联系邮箱:[email protected]
标准仓储
///
/// 标准仓储接口
///
public interface IRepository
{
#region Methods
///
/// 删除记录
///
/// 操作是否成功
/// 需要操作的实体类.
bool Delete(T entity) where T : ModelBase;
///
/// 条件判断是否存在
///
/// 是否存在
/// 判断条件委托
bool Exist(Expression> predicate = null) where T : ModelBase;
///
/// 根据id获取记录
///
/// 记录
/// id.
T GetByKeyId(object id) where T : ModelBase;
///
/// 条件获取记录集合
///
/// 集合
/// 筛选条件.
List GetList(Expression> predicate = null) where T : ModelBase;
///
/// 条件获取记录第一条或者默认
///
/// 记录
/// 筛选条件.
T GetFirstOrDefault(Expression> predicate = null) where T : ModelBase;
///
/// 创建一条记录
///
/// 操作是否成功.
/// 实体类记录.
bool Create(T entity) where T : ModelBase;
///
/// 条件查询
///
/// IQueryable
/// 筛选条件.
IQueryable Query(Expression> predicate = null) where T : ModelBase;
///
/// 根据记录
///
/// 操作是否成功.
/// 实体类记录.
bool Update(T entity) where T : ModelBase;
#endregion Methods
}
数据访问上下文接口
public interface IDbContext : IDisposable, IRepository, IUnitOfWork
{
///
/// 执行Sql 脚本查询
///
/// Sql语句
/// 参数
/// 集合
IEnumerable SqlQuery(string sql, IDbDataParameter[] parameters);
}
数据访问上下文工厂
public interface IDatabaseContextFactory
{
///
/// Create this instance.
///
/// The create.
IDbContext Create();
}
基于EF的DbContext
public abstract class EfDbContextBase : DbContext, IDbContext
{
#region Constructors
///
/// 构造函数
///
/// dbConnection
protected EfDbContextBase(DbConnection dbConnection)
: base(dbConnection, true)
{
Configuration.LazyLoadingEnabled = false; //将不会查询到从表的数据,只会执行一次查询,可以使用 Inculde 进行手动加载;
Configuration.ProxyCreationEnabled = false;
Configuration.AutoDetectChangesEnabled = false;
}
#endregion Constructors
#region Fields
///
/// 获取 是否开启事务提交
///
public virtual bool TransactionEnabled => Database.CurrentTransaction != null;
#endregion Fields
#region Methods
///
/// 显式开启数据上下文事务
///
/// 指定连接的事务锁定行为
public void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified)
{
if (!TransactionEnabled) Database.BeginTransaction(isolationLevel);
}
///
/// 提交当前上下文的事务更改
///
/// 提交数据更新时发生异常:" + msg
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;
}
}
///
/// 创建记录
///
/// 操作是否成功
/// 需要操作的实体类.
public bool Create(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;
}
///
/// 创建记录集合
///
/// 操作是否成功.
/// 实体类集合.
public bool Create(IEnumerable 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;
}
///
/// 删除记录
///
/// 操作是否成功
/// 需要操作的实体类.
public bool Delete(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;
}
///
/// 条件判断是否存在
///
/// 是否存在
/// 判断条件委托
public bool Exist(Expression> predicate = null)
where T : ModelBase
{
return predicate == null ? Set().Any() : Set().Any(predicate);
}
///
/// 根据id获取记录
///
/// 记录
/// id.
public T GetByKeyId(object id)
where T : ModelBase
{
ValidateOperator.Begin().NotNull(id, "Id");
return Set().Find(id);
}
///
/// 条件获取记录集合
///
/// 集合
/// 筛选条件.
public List GetList(Expression> predicate = null)
where T : ModelBase
{
IQueryable query = Set();
if (predicate != null) query = query.Where(predicate);
return query.ToList();
}
///
/// 条件获取记录第一条或者默认
///
/// 记录
/// 筛选条件.
public T GetFirstOrDefault(Expression> predicate = null)
where T : ModelBase
{
IQueryable query = Set();
if (predicate != null)
return query.FirstOrDefault(predicate);
return query.FirstOrDefault();
}
///
/// 条件查询
///
/// IQueryable
/// 筛选条件.
public IQueryable Query(Expression> predicate = null)
where T : ModelBase
{
IQueryable query = Set();
if (predicate != null) query = query.Where(predicate);
return query;
}
///
/// 显式回滚事务,仅在显式开启事务后有用
///
public void Rollback()
{
if (TransactionEnabled) Database.CurrentTransaction.Rollback();
}
///
/// 执行Sql 脚本查询
///
/// Sql语句
/// 参数
/// 集合
public IEnumerable SqlQuery(string sql, IDbDataParameter[] parameters)
{
ValidateOperator.Begin()
.NotNullOrEmpty(sql, "Sql语句");
// ReSharper disable once CoVariantArrayConversion
return Database.SqlQuery(sql, parameters);
}
///
/// 根据记录
///
/// 操作是否成功.
/// 实体类记录.
public bool Update(T entity)
where T : ModelBase
{
ValidateOperator.Begin().NotNull(entity, "需要更新的数据记录");
bool result;
try
{
var set = Set();
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();
//if (!_sampleService.Exist(ent => ent.ID == _testID))
//{
// _sampleService.Create(new EFSample() { UserName = _testName, ID = _testID });
//}
}
///
/// 创建测试
///
[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 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 actual = _sampleService.SqlQuery(sql, parameter);
Assert.IsNotNull(actual);
CollectionAssert.AllItemsAreNotNull(actual);
}
///
/// 多线程测试
///
[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以及事务处理,从而开发中关注业务即可;
- 小弟不才,大佬轻拍;