介绍
这个帮助器的目标是使用实体框架(CodeFirst)开发一个通用的 - 可重用的数据访问帮助程序,而其动机是使用泛型和代理消除冗余代码。
帮助者分为两个部分,第一部分是查询(检索)业务,第二个是将数据库的更改保存到同步和异步的数据库中。
背景
这个帮助者提出使用这些技术.NET 4.5(C#5),实体框架6(CodeFirst)。此外,您需要具有关于async
/ await
代码的适度知识。
详细内容
这里的泛型意味着将泛型应用于采用代理类型的方法Action
,以防万一它不返回,或者类型Func
返回结果 - 作为一个参数,而这个参数又将类型参数DBContext
作为基类继承自具体类。
每个方法根据其作用封装以下逻辑:
- 启动一个具体的实体框架上下文
using
- 使用locked(
Default
)或unlocking(IsolationLevel.ReadUncommitted
)表开始事务范围 try
/catch
身体- 委托执行
- 提交和回滚逻辑,以防它是由一组事务组成的原子事务
- 结果返回类型布尔值,表示查询/保存状态,或使用泛型预定义的类型。
- 异步逻辑
- 日志异常
所有这些逻辑不会被写入您的基于业务的数据访问逻辑,因此冗余代码被消除。
动机
当我们编写一个使用EF&Linq访问数据库的简单逻辑时,它看起来像这样:
public static List<Employee> GeAllEmployees()
{
try
{
using (var northwindContext = new NorthwindDBContext())
{
var query = from e in northwindContext.Employees select e;
return query.ToList();
}
}
catch (Exception ex)
{
// Log Error
}
}
所以,我必须使这个代码冗余与一个新的业务(例如GetEmployeeOrders
)。另外,如果我必须访问另一个数据库,这意味着另一个DBContext
,我必须使这个逻辑冗余!
在这里,通用代表和代表作为这两个问题的解决方案。所以,我创建了一个 public static class
名为DALHelper
包含以下七个static
方法。
1查询
所有检索的方法也可用于保存对数据库的更改。
1.1默认值
以下代码片段是锁定表,这是启动新的代码的默认行为 DbContext
。
public static bool GenericRetrival<T>(Action<T> action) where T : DbContext, new()
{
try
{
using (var context = new T())
{
action(context);
return true;
}
}
catch (Exception ex)
{
// Log Error
return false;
}
}
用法
public List<Employee> GeAllEmployees()
{
List<Employee> result= null;
bool success = DALHelper.GenericRetrival<NorthwindDBContext>((northwindContext) =>
{
result = (from e in northwindContext.Employees select e).ToList();
});
return result;
}
1.2查询通用结果
这里我们将TResult
类型DBContext
的代表标识为类型的泛型,Func
返回TResult
类型的对象。
public static TResult GenericResultRetrival<T, TResult>(Func<T, TResult> func) where T : DbContext, new()
where TResult : new()
{
try
{
using (var context = new T())
{
TResult res = func(context);
return res;
}
}
catch (Exception ex)
{
// Log Error
return default(TResult);
}
}
用法
public List<Employee> GeAllEmployees()
{
List<Employee> result = DALHelper.GenericResultRetrival<NorthwindDBContext,List<Employee>>((northwindContext) =>
{
return (from e in northwindContext.Employees select e).ToList();
});
return result;
}
1.3 异步查询
public static async Task<TResult> GenericRetrivalAsync<T,
TResult>(Func<T, Task<TResult>> func)
where T : DbContext, new()
where TResult : new()
{
try
{
using (var context = new T())
{
return await func(context);
}
}
catch (Exception ex)
{
// Log Error
return default(TResult);
}
}
用法
public async Task<List<Employee>> GetAllEmployeesAsync()
{
return await DALHelper.GenericRetrivalAsync<NorthwindDBContext, List<Employee>>(async (northwindContext) =>
{
return await (from e in northwindContext.Employees select e).ToListAsync();
});
}
1.4一个长时间的查询,没有异步锁定表
public static async Task<TResult>
GenericResultNoLockLongRetrivalAsync<T,TResult>(Func<T, Task<TResult>> func)
where T : DbContext, new()
where TResult : new()
{
try
{
using (var context = new T())
{
((IObjectContextAdapter)context).ObjectContext.CommandTimeout = 0;
using (var dbContextTransaction =
context.Database.BeginTransaction(IsolationLevel.ReadUncommitted))
{
return await func(context);
}
}
}
catch (Exception exception)
{
// Log Error
return default(TResult);
}
}
1.5从两个上下文异步查询
public static async Task<object>
GenericTwiceContextsRetrivalAsync<T1, T2>(Func<T1, T2, Task<object>> func)
where T1 : DbContext, new()
where T2 : DbContext, new()
{
try
{
using (var context1 = new T1())
{
using (
var dbContextTransaction1 = context1.Database.BeginTransaction(IsolationLevel.ReadUncommitted))
{
using (var context2 = new T2())
{
using (
var dbContextTransaction2 =
context2.Database.BeginTransaction(IsolationLevel.ReadUncommitted)
)
{
return await func(context1, context2);
}
}
}
}
}
catch (Exception exception)
{
// Log Error
return null;
}
}
用法
public async Task<object> GetDistributedDataAsync()
{
return await DALHelper.GenericTwiceContextsRetrivalAsync<NorthwindDBContext, AdventureWorkDBContext>(async
(northwindContext, advantureContext) =>
{
var employees = (from e in northwindContext.Employees select e).ToListAsync();
var cutomers = (from c in advantureContext.Customers select c).ToListAsync();
await Task.WhenAll(employees, cutomers);
return new
{
EmployeeList = employees.Result,
PersonList = cutomers.Result
};
});
}
所以设计将是:
2储蓄
2.1通用安全储存
我称之为安全,因为它可以将一组事务视为具有提交/回滚逻辑的 原子。
public static bool GenericSafeTransaction<T>(Action<T> action) where T : DbContext, new()
{
using (var context = new T())
{
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
action(context);
dbContextTransaction.Commit();
return true;
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
// Log Error
return false;
}
}
}
}
用法
public bool AddMultipleRecords(Employee newEmp, Supplier newSup)
{
return DALHelper.GenericSafeTransaction<NorthwindDBContextgt;(northwindContext =>
{
northwindContext.Employees.Add(newEmp);
northwindContext.SaveChanges();
northwindContext.Suppliers.Add(newSup);
northwindContext.SaveChanges();
});
}
2.2 异步保存
public static async Task<int?> GenericSafeTransactionAsync<T>(Action<T> action)
where T : DbContext, new()
{
using (var context = new T())
{
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
action(context);
int affectedRecords = await context.SaveChangesAsync();
dbContextTransaction.Commit();
return affectedRecords;
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
// Log Error
return null;
}
}
}
}
用法
return await DALHelper.GenericSafeTransactionAsync<NorthwindDBContext>( async (northwindContext) =>
{
northwindContext.Employees.Add(newEmp);
});
【本文由“筱乐微讯账号”发布,2017年10月22日】