EFCore的数据仓储模式
在EntityFramworkCore 配置种子数据中有降到如何配置种子数据,接下里就讲一讲数据仓储模式。
目录
1.动机
1.1 时下数据驱动应用是如何访问数据库
1.2Repository Design Pattern
2.实现
2.1具体仓储的实现
2.2泛型仓储
1.动机
1.1 时下数据驱动应用是如何访问数据库
传统的数据库应用结构如下:
从上图可以看出,对雇员的CURD操作是直接通过controller访问EFcore 的data context,EF将来自上层的CURD操作转化为SQL语句。那这样做有什么缺点呢:当然上述方法肯定是行之有效的,但是这样我们会把对数据的查询,修改,删除操作深度绑定到Controller这一层,这样的设计或者实现会造成代码冗余,且不利于后续维护,一旦数据访问逻辑发生了一点点小改动都需要对Controller进行修改。
1.2Repository Design Pattern
所以,这里就引入了数据仓储模式,这也是成为业界通用的做法,引入数据仓储模式后的架构如下:
简而言之就是我们在领域层和数据映射层之间加了一层,这一层类似于集合访问接口,专门用于领域层访问数据。换句话说,Repository Design Pattern在数据访问层和其它应用层之间扮演者一个中间人,应用获取数据的所有操作都交给这个中间人。好处是自然而然的将上层应用和低层数据访问隔离开来,当你改动一端时,不用修改另一端。而且测试Controller也会变得简单,你可以模拟一个内存数据库,而不用真的配置一个真实的数据库。
2.实现
2.1具体仓储的实现
为了方便依赖注入,我们首先定义一个仓库的接口:
简单起见我就定义下面几个方法(你可以根据具体的业务添加):
using RepositoryPatternStudy.Models;namespace RepositoryPatternStudy.Repository
{public interface IEmployeeRepository{IEnumerable<Employee> GetAll();Employee GetById(int id);void Insert(Employee employee);void Update(Employee employee);void Delete(Employee employee);void Save();}
}
下面添加具体的实现:
public class EmployeeRepository : IEmployeeRepository,IDisposable{private readonly EmployeeDbContext _context;public EmployeeRepository(EmployeeDbContext context){_context = context;}public void Delete(int employeeID){Employee employee = _context.Employees.Find(employeeID);_context.Employees.Remove(employee);}public IEnumerable<Employee> GetAll(){return _context.Employees.ToList();}public Employee? GetById(int id)=> _context.Employees.Find(id);public void Insert(Employee employee)=>_context.Employees.Add(employee);public void Save()=>_context.SaveChanges();public void Update(Employee employee)=>_context.Entry(employee).State=EntityState.Modified;public bool disposed=false;protected virtual void Dispose(bool disposing){if(!disposed){if(disposing)_context.Dispose();}disposed=true;}public void Dispose(){Dispose(true);GC.SuppressFinalize(this);}}
为了验证我们的正确性,我们可以新建一个EmployeeController:
public class EmployeeController : Controller{private readonly IEmployeeRepository _employeeRepository;public EmployeeController(IEmployeeRepository employeeRepository)=>_employeeRepository = employeeRepository;[HttpGet]public List<Employee> Index(){var model=_employeeRepository.GetAll();return model.ToList();}
}
(在这里用了依赖注入,所以要记得在配置文件中添加服务:)
builder.Services.AddTransient<IEmployeeRepository,EmployeeRepository>();
运行程序打开Employee对于的页面:
可以看到成功的拿到了数据库的数据。至此具体的仓储就实现完成了!
当然,你可以添加相应的视图,使得显示效果更更好:
@model IEnumerable<RepositoryUsingEFinMVC.DAL.Employee>
@{ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>@Html.ActionLink("Add Employee", "AddEmployee")
</p>
<table class="table"><tr><th>@Html.DisplayNameFor(model => model.Name)</th><th>@Html.DisplayNameFor(model => model.Gender)</th><th>@Html.DisplayNameFor(model => model.Salary)</th><th>@Html.DisplayNameFor(model => model.Dept)</th><th></th></tr>@foreach (var item in Model){<tr><td>@Html.DisplayFor(modelItem => item.Name)</td><td>@Html.DisplayFor(modelItem => item.Gender)</td><td>@Html.DisplayFor(modelItem => item.Salary)</td><td>@Html.DisplayFor(modelItem => item.Dept)</td><td>@Html.ActionLink("Edit", "EditEmployee", new { EmployeeId = item.EmployeeID }) |@Html.ActionLink("Delete", "DeleteEmployee", new { EmployeeId = item.EmployeeID })</td></tr>}
</table>
显示效果如下:
2.2泛型仓储
因为我们只有一个实体类型:Employee,但实际上的项目实体肯定不止一个,可能还有订单order,顾客Custome等,如果没有泛型仓储,我们可能需要为每个实体构建一个仓库,这是很麻烦的。
有了前面的基础,我们构建泛型仓库就简单很多,首先定义一个泛型仓库接口:
public interface IGenericRepository<T> where T:class{IEnumerable<T> GetAll();T GetById(object id);void Insert(T obj);void Update(T obj);void Delete(object id);void Save();}
然后实现它:
public class GenericRepository<T> : IGenericRepository<T> where T : class{private readonly EmployeeDbContext _context;private readonly DbSet<T> table;public GenericRepository(EmployeeDbContext context){_context = context;table = context.Set<T>();}public void Delete(object id){T existing=table.Find(id);table.Remove(existing);}public IEnumerable<T> GetAll()=>table.ToList();public T GetById(object id)=> table.Find(id);public void Insert(T obj)=>table.Add(obj);public void Save()=>_context.SaveChanges();public void Update(T obj){table.Attach(obj);_context.Entry(obj).State = EntityState.Modified;}}
将泛型仓储注册到服务:
builder.Services.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>));
然后在Controller中将泛型仓储替换原来的仓储:
private readonly IEmployeeRepository _employeeRepository;private readonly IGenericRepository<Employee> _repository;public EmployeeController(IEmployeeRepository employeeRepository, IGenericRepository<Employee> genericRepository){_employeeRepository = employeeRepository;_repository = genericRepository;}[HttpGet]public ActionResult Index(){//var model=_employeeRepository.GetAll();var model = _repository.GetAll();return View(model);
可以得到相同的运行结果(我这里同时将两种类型的仓储都注册进去了)。
2.3 同时使用两种仓库
泛型仓储一般是比较通用的方法,也就是常见的CURD,一旦想定制化仓库,比扩展一些功能,则需要自行实现,但是如果已经有了泛型仓储,那么通过继承,我们可以只实现不同的部分,这样也带来了相当大的遍历。
操作如下:
public interface IEmployeeRepositoryEx:IGenericRepository<Employee>{IEnumerable<Employee> GetEmployeesByGender(string gender);IEnumerable<Employee> GetEmployeesByDepartment(string Dept);}
上面是一个扩充了两个方法的新接口,其实现如下:
public class EmployeeeRepositoryEx : GenericRepository<Employee>, IEmployeeRepositoryEx{// private readonly IGenericRepository<Employee> _repository;// private readonly IEmployeeRepositoryEx _employeeRepositoryEx;private readonly EmployeeDbContext _context;public EmployeeeRepositoryEx(EmployeeDbContext context):base(context)// IGenericRepository<Employee> genericRepository,IEmployeeRepositoryEx employeeRepositoryEx):base(context){// _repository = genericRepository;// _employeeRepositoryEx = employeeRepositoryEx;_context = context;}public IEnumerable<Employee> GetEmployeesByDepartment(string Dept){return _context.Employees.Where(x=>x.Dept == Dept);}public IEnumerable<Employee> GetEmployeesByGender(string gender){return _context.Employees.Where(x=>x.Gender == gender);}}
将IEmployeeRepository注册,并替换后,可以同时使用泛型接口和新接口的方法,从而达到了定制化扩展,同样你可以放在EmployeeController中尝试。
到此为止,仓储模型就基本讲完了,
EFCore的数据仓储模式相关推荐
- 数据仓储模式UnitOfWorks和Repository的实现
数据仓储模式UnitOfWorks和Repository的实现( 网上看了相关内容关于UnitOfWorks和Repository的数据仓储模式的实现,也来动手搭建下. ORM使用微软自己的EF来实现 ...
- 仓储模式到底是不是反模式?
[导读]仓储模式我们已耳熟能详,但当我们将其进行应用时,真的是那么得心应手吗?确定是解放了生产力吗?这到底是怎样的一个存在,确定不是反模式? 一篇详文我们探讨仓储模式,这里仅我个人的思考,若有更深刻的 ...
- .NET仓储模式高级用例
\ 主要结论 \\ 如果需要执行基本CURD之外的其他操作,此时就有必要使用仓储(Repository).\\t 为了促进测试工作并改善可靠性,应将仓储视作可重复使用的库(Library).\\t 将 ...
- 使用实体框架、Dapper和Chain的仓储模式实现策略
\ 关键要点: \ Dapper这类微ORM(Micro-ORM)虽然提供了最好的性能,但也需要去做最多的工作.\ 在无需复杂对象图时,Chain这类Fluent ORM更易于使用.\ 对实体框架(E ...
- 5.在MVC中使用泛型仓储模式和工作单元来进行增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...
- Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)
很久没有写博客了,一些读者也经常问问一些问题,不过最近我确实也很忙,除了处理日常工作外,平常主要的时间也花在了继续研究微软的实体框架(EntityFramework)方面了.这个实体框架加入了很多特性 ...
- ASP.NET Core 中的规约模式(Specification Pattern )——增强泛型仓储模式
原文链接:https://codewithmukesh.com/blog/specification-pattern-in-aspnet-core/ 在本文中,我们将讨论在 ASP.NET Core ...
- MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用
MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用 原文:MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用 摘要: 第一阶段1~10篇已经覆盖了MVC开发必要的基本知识. ...
- 云计算是否为数据仓储做好了准备呢?
原文链接:http://blogs.sap.com/innovation/cloud-computing/is-cloud-ready-for-data-warehousing-022232<? ...
最新文章
- 20种看asp源码的方法及工具
- 一家全是学霸!王力宏的哥哥也是博士,近日获5000余万拨款用于这项研究
- python转exe 体积_[转]用PyInstaller将python转成可执行文件exe笔记
- poj 1328 Radar Installation
- Python-爬取中国天气网天气并通过邮箱定时发送
- Android Studio 的 build 过程
- 怎么才能学好Java编程写好Java代码?
- 监控oracle数据io,Prometheus监控Oracle数据库
- native 真机测试react_react-native真机调试出现Failed to install all
- Lubuntu16.4.3定制教程
- [云计算]网线的标签格式
- Android 11 Meetup 上海站!来了!
- [51nod]2128 前缀异或【数学题】
- JAVA随机数生成 | Math.random()方法 | 随机生成int、double类型
- java前端导入excel_Java之导入Excel Vue框架前端篇
- mysql只导出表数据_MySQL 如何只导出 指定的表 的表结构和数据 ( 转 )
- 如何搭建内测托管平台?有可以直接用的内测托管平台吗?
- linux sort排序及取前几条数据
- LA 3708 - Graveyard 墓地雕塑
- Zephyr 3.2 弃用devicetree 中node 里的label property