前言

之前我们系统学习了EntityFramework,个人觉得有些东西不能学了就算完了,必须要学以致用,在Web API上也少不了增(C)、删(D)、改(U)、查(R)。鉴于此,我们通过EF来实现Web API上的增删改查。

之前对于EF的基本操作都是很零散的,我们应该对于CRUD都是通过完整封装来实现,并且也显得比较专业,接下来首先对EF利用Responsitory仓储模式进行完整封装。

EntityFramework完整封装

我们建立一个Core(核心类库),里面存放有关EF的完成封装。

第一步

建立所有实体的基类,将实体的公共属性放入其中,取为BaseEntity

    public class BaseEntity<T>{public T Id { get; set; }}

第二步

建立仓储接口IRepository,包括基本的增、删、改、查等方法

    public interface IRepository<TEntity> where TEntity : class{/// <summary>/// 获得数据列表/// </summary>/// <returns></returns>IQueryable<TEntity> GetList();/// <summary>/// 通过id获得实体/// </summary>/// <param name="id"></param>/// <returns></returns>TEntity GetById(object id);/// <summary>/// 添加实体/// </summary>/// <param name="entity"></param>int Insert(TEntity entity);/// <summary>/// 添加实体集合/// </summary>/// <param name="entities"></param>int Insert(IEnumerable<TEntity> entities);/// <summary>/// 删除实体/// </summary>/// <param name="entity"></param>int Delete(TEntity entity);/// <summary>/// 根据条件删除实体/// </summary>/// <param name="entities"></param>int DeleteByRequirement(Expression<Func<TEntity, bool>> func);/// <summary>/// 更新实体/// </summary>/// <param name="entity"></param>int Update(TEntity entity);/// <summary>/// 更新实体集合/// </summary>/// <param name="entities"></param>int Update(IEnumerable<TEntity> entities);}

第三步

利用仓储服务RepositoryService实现上述仓储接口IRepository

    public class RepositoryService<TEntity> : IRepository<TEntity> where TEntity : class{private IDbContext Context;private bool IsNoTracking;/// <summary>/// 获取实体集合/// </summary>private IDbSet<TEntity> Entities{get{return this.Context.Set<TEntity>();}}private DbEntityEntry Entry(TEntity entity){return this.Context.Entry<TEntity>(entity);}public RepositoryService(IDbContext context, bool isNoTracking){this.Context = context;this.IsNoTracking = isNoTracking;}/// <summary>/// 获取所有数据/// </summary>/// <returns></returns>public IQueryable<TEntity> GetList(){if (!IsNoTracking)return this.Entities.AsQueryable();elsereturn this.Entities.AsNoTracking().AsQueryable();}/// <summary>/// 通过id获取实体/// </summary>/// <param name="id"></param>/// <returns></returns>public TEntity GetById(object id){return Entities.Find(id);}/// <summary>/// 添加实体/// </summary>/// <param name="entity"></param>public int Insert(TEntity entity){Entities.Add(entity);return this.Context.SaveChanges();}public int Insert(IEnumerable<TEntity> entities){if (entities == null)throw new ArgumentNullException("entities");foreach (var entity in entities){Entities.Add(entity);}return this.Context.SaveChanges();}/// <summary>/// 删除实体/// </summary>/// <param name="entity"></param>public int Delete(TEntity entity){if (!IsNoTracking)this.Entities.Remove(entity);elsethis.Entities.Attach(entity);this.Entities.Remove(entity);return this.Context.SaveChanges();}public int DeleteByRequirement(Expression<Func<TEntity, bool>> func){var list = GetList().Where(func).ToList();list.ForEach(e =>{if (!IsNoTracking)this.Entities.Remove(e);elsethis.Entities.Attach(e);this.Entities.Remove(e);});return this.Context.SaveChanges();}/// <summary>/// 更新实体/// </summary>/// <param name="entity"></param>public int Update(TEntity entity){if (!IsNoTracking)return this.Context.SaveChanges();elsethis.Context.Entry(entity).State = EntityState.Modified;return this.Context.SaveChanges();}public int Update(IEnumerable<TEntity> entities){if (entities == null)throw new ArgumentNullException("enetities");if (!IsNoTracking)return this.Context.SaveChanges();elseforeach (var t in entities){this.Context.Entry(t).State = EntityState.Modified;}return this.Context.SaveChanges();}/// <summary>/// 释放资源/// </summary>public void Dispose(){Dispose(true);GC.SuppressFinalize(this);}protected virtual void Dispose(bool disposing){if (disposing){if (Context != null){this.Context.Dispose();this.Context = null;}}}}

第四步

用接口IDbContext封装EF上下文DbContext中的公共方法

    public interface IDbContext{/// <summary>/// 获得实体集合/// </summary>/// <typeparam name="TEntity"></typeparam>/// <returns></returns>IDbSet<TEntity> Set<TEntity>() where TEntity : class;/// <summary>/// 执行存储过程/// </summary>/// <typeparam name="TEntity"></typeparam>/// <param name="commandText"></param>/// <param name="parameters"></param>/// <returns></returns>IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters)where TEntity : class;/// <summary>/// 执行SQL语句查询/// </summary>/// <typeparam name="TElement"></typeparam>/// <param name="sql"></param>/// <param name="parameters"></param>/// <returns></returns>IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters);DbEntityEntry Entry<TEntity>(TEntity entity) where TEntity : class;/// <summary>/// 保存数据/// </summary>/// <returns></returns>int SaveChanges();/// <summary>/// 变更追踪代码/// </summary>bool ProxyCreationEnabled { get; set; }/// <summary>/// DetectChanges方法自动调用/// </summary>bool AutoDetectChangesEnabled { get; set; }/// <summary>/// 调用Dispose方法/// </summary>void Dispose();}

第五步

实现EF上下文中的数据库连接、模型初始化以及映射等(也可以手动关闭全局变更追踪相对比较灵活)

    public class EFDbContext : DbContext, IDbContext{public EFDbContext(string connectionString): base(connectionString){ }static EFDbContext(){Database.SetInitializer<EFDbContext>(new DropCreateDatabaseIfModelChanges<EFDbContext>());}/// <summary>/// 一次性加载所有映射/// </summary>/// <param name="modelBuilder"></param>protected override void OnModelCreating(DbModelBuilder modelBuilder){var typesToRegister = Assembly.GetExecutingAssembly().GetTypes().Where(type => !String.IsNullOrEmpty(type.Namespace)).Where(type => type.BaseType != null && type.BaseType.IsGenericType &&type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));foreach (var type in typesToRegister){dynamic configurationInstance = Activator.CreateInstance(type);modelBuilder.Configurations.Add(configurationInstance);}base.OnModelCreating(modelBuilder);}/// <summary>/// 获得实体集合/// </summary>/// <typeparam name="TEntity"></typeparam>/// <returns></returns>public new IDbSet<TEntity> Set<TEntity>() where TEntity : class{return base.Set<TEntity>();}/// <summary>/// 实体状态/// </summary>/// <typeparam name="TEntity"></typeparam>/// <param name="entity"></param>/// <returns></returns>public new DbEntityEntry Entry<TEntity>(TEntity entity) where TEntity : class{return base.Entry<TEntity>(entity);}/// <summary>/// 执行存储过程/// </summary>/// <typeparam name="TEntity"></typeparam>/// <param name="commandText"></param>/// <param name="parameters"></param>/// <returns></returns>public IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : class{if (parameters != null && parameters.Length > 0){for (int i = 0; i <= parameters.Length - 1; i++){var p = parameters[i] as DbParameter;if (p == null)throw new Exception("Not support parameter type");commandText += i == 0 ? " " : ", ";commandText += "@" + p.ParameterName;if (p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Output){commandText += " output";}}}var result = this.Database.SqlQuery<TEntity>(commandText, parameters).ToList();bool acd = this.Configuration.AutoDetectChangesEnabled;try{this.Configuration.AutoDetectChangesEnabled = false;for (int i = 0; i < result.Count; i++)result[i] = this.Set<TEntity>().Attach(result[i]);}finally{this.Configuration.AutoDetectChangesEnabled = acd;}return result;}/// <summary>/// SQL语句查询/// </summary>/// <typeparam name="TElement"></typeparam>/// <param name="sql"></param>/// <param name="parameters"></param>/// <returns></returns>public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters){return this.Database.SqlQuery<TElement>(sql, parameters);}/// <summary>/// 当查询或者获取值时是否启动创建代理/// </summary>public virtual bool ProxyCreationEnabled{get{return this.Configuration.ProxyCreationEnabled;}set{this.Configuration.ProxyCreationEnabled = value;}}/// <summary>/// 当查询或者获取值时指定是否开启自动调用DetectChanges方法/// </summary>public virtual bool AutoDetectChangesEnabled{get{return this.Configuration.AutoDetectChangesEnabled;}set{this.Configuration.AutoDetectChangesEnabled = value;}}}

以上就是对利用EntityFramework来实现基本操作的完整封装。接下来就是相关类以及映射(场景:一个Student对应一个Flower,而一个Flower对应多个Student)

Student

    public class Student : BaseEntity<int>{public string Name { get; set; }public int FlowerId { get; set; }public virtual Flower Flower { get; set; }}

Flower

   public class Flower : BaseEntity<int>{public string Remark { get; set; }public virtual ICollection<Student> Students { get; set; }}

相关映射

    public class StudentMap:EntityTypeConfiguration<Student>{public StudentMap(){ToTable("Student");HasKey(p => p.Id);Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);HasRequired(p => p.Flower).WithMany(p => p.Students).HasForeignKey(p => p.FlowerId);}}public class FlowerMap:EntityTypeConfiguration<Flower>{public FlowerMap(){ToTable("Flower");HasKey(p => p.Id);Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);}}

CRUD

接下来就是Web API控制器中执行增、删等操作,我们创建一个StudentController控制器,然后首先创建仓储服务。(执行Action方法,依据默认约定,未添加特性)

        public IRepository<Student> _repository;public EFDbContext _ctx;public StudentController(){_ctx = new EFDbContext("DBByConnectionString");_repository = new RepositoryService<Student>(_ctx, true);  //关闭局部变更追踪}

执行R操作(即默认请求到HttpGet方法)

        public IEnumerable<Student> GetAllStudent(){return _repository.GetList().Select(d => new Student { Name = d.Name, Flower = d.Flower, Id = d.Id }).ToList();}

当执行此查询操作时却出错了,真遗憾:

上述修改如下即可:

 return _repository.GetList().ToList().Select(d => new Student { Name = d.Name, Flower = d.Flower, Id = d.Id }).ToList();

不知道还有没有更好的解决方案,用ToList直接将所有数据进行加载到内存中,在性能上消耗比较大。(期待你的解决方案)

特此记录

在此感谢园友(_天光云影)给出的解决方案,在GetList之后利用 Linq 进行Select,最后进行ToList即可!!!

执行CUD等操作

       public Student GetStudentById(int id){var student = _repository.GetById(id);if (student == null)throw new HttpResponseException(HttpStatusCode.NotFound);elsereturn student;}//添加操作(HttpPost)public HttpResponseMessage PostStudent(Student stu){var insertStudent = _repository.Insert(stu);var response = Request.CreateResponse<Student>(HttpStatusCode.Created, stu);string uri = Url.Link("DefaultApi", new { id = stu.Id });response.Headers.Location = new Uri(uri);return response;}//更新操作(HttpPut)public void PutStudent(int id, Student stu){stu.Id = id;if (_repository.Update(stu) <= 0){throw new HttpResponseException(HttpStatusCode.NotFound);}}//删除操作(HttpDelete)public void DeleteStudent(int id){Student stu = _repository.GetById(id);if (stu == null){throw new HttpResponseException(HttpStatusCode.NotFound);}_repository.Delete(stu);}

View Code

总结

这节主要介绍了利用仓储模式完整封装EF来进行Web API基本操作,基本操作中关于返回状态码等信息,无非就是以下几个对象

HttpResponseException  返回异常HttpResponseMessage   返回信息(诸如状态码等)HttpStatusCode       状态码枚举(如页面未找到等)

源代码下载

【WebAPI之EntityFramework】

转载于:https://www.cnblogs.com/CreateMyself/p/4820121.html

Web APi之EntityFramework【CRUD】(三)相关推荐

  1. Contact Manager Web API 示例[1]CRUD 操作

    联系人管理器web API是一个Asp.net web api示例程序,演示了通过ASP.NET Web API 公开联系信息,并允许您添加和删除联系人,示例地址http://code.msdn.mi ...

  2. WEB API新增整理(三)

    一.Gamepad API 简介: 给予开发者一种简单.统一的方式来识别并响应游戏控制器(手柄).其中包含了三个接口.两个事件.一个特殊函数,用来响应控制器的连接与断开.获取其他关于控制器的信息以及识 ...

  3. 使用VS 2019,.NET Core 3和Web API创建ASP.NET Core Blazor CRUD应用程序

    目录 介绍 Blazor Blazor客户端应用程序 Blazor服务器应用程序 背景 先决条件 使用代码 第1步-创建数据库和表 第2步-创建ASP.NET Core Blazor服务器应用程序 运 ...

  4. 使用Entity Framework和Web API的ASP.NET Core Blazor CRUD

    目录 介绍 背景 先决条件 使用代码 第1步--创建数据库和表 第2步--创建ASP.NET Core Blazor应用程序 ASP.NET Core Blazor解决方案的新增功能是什么? 客户端项 ...

  5. 我所理解的RESTful Web API [设计篇]

    <我所理解的RESTful Web API [Web标准篇]>Web服务已经成为了异质系统之间的互联与集成的主要手段,在过去一段不短的时间里,Web服务几乎清一水地采用SOAP来构建.构建 ...

  6. 学习笔记-Spring Boot 开发 RESTful Web API(一)

    题记: 本篇是Spring Boot 开发学习系列中基础知识学习的一部分,为 RESTful Web API 相关基础知识,为实践操作奠定理论基础. REST不是一个标准,而是一种软件应用架构风格.基 ...

  7. 返璞归真 asp.net mvc (10) - asp.net mvc 4.0 新特性之 Web API

    返璞归真 asp.net mvc (10) - asp.net mvc 4.0 新特性之 Web API 原文:返璞归真 asp.net mvc (10) - asp.net mvc 4.0 新特性之 ...

  8. java调用asp.net webapi_通过HttpClient 调用ASP.NET Web API示例

    在前面两篇文章中我们介绍了ASP.NET Web API的基本知识和原理,并且通过简单的实例了解了它的基本(CRUD)操作.我们是通过JQuery和Ajax对Web API进行数据操作.这一篇我们来介 ...

  9. 【ASP.NET Web API教程】3.3 通过WPF应用程序调用Web API(C#)

    注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 3.3 Calling a Web API From a WPF Application ...

最新文章

  1. Map-Reduce的过程解析
  2. ASP.NET PipeLine #Reprinted#
  3. windows无法安装iis信息服务器,windows server 2016 安装iis教程
  4. 2021-08-10 C3P0连接池
  5. 16.[个人]C++线程入门到进阶(16)----线程函数:CreateThread与_beginthread
  6. Excel之VBA简单宏编程
  7. java sqrt函数源码_Java sqrt源码解析
  8. .NET 6 中的 Http Logging 中间件
  9. excel求四分位数(QUARTILE 函数)
  10. Task 编程中的异常处理
  11. FPGA学习日志——分频与降频divider
  12. Win+E快速打开我的电脑方式设置方式
  13. mysql异地双活架构,银行跨数据中心数据库双活架构设计:五大难点攻克
  14. 安卓修改电池容量教程_安卓手机端修改电池电量图标的教程
  15. 【毕业设计】基于stm32的便携式U盘设计与实现 - stm32制作U盘
  16. 做管理层需要具备哪些能力?做管理的核心是什么
  17. 详解GPFS文件系统架构、组网和Building Block
  18. 机器学习之线性回归(Linear Regression)算法
  19. 用纯CSS3实现闪闪发光的动画
  20. 流变学基础 -- 粘度与粘弹性测试

热门文章

  1. 计算机无法安装手机数据线,连接电脑,详细教您手机数据线连接电脑没反应该怎么解决...
  2. 绝地求生测试服画面优化软件,绝地求生大逃杀 画质优化补丁
  3. log4j:WARN Please initialize the log4j system properly
  4. 软件体系架构:RM-ODP参考模型简介
  5. velocity用法简单实例说明 .
  6. PostgreSQL 8.0 中文手册
  7. git删除远程服务的文件夹
  8. IDEA使用Maven打包时如何去掉测试阶段
  9. Vim强制写入w!的分析
  10. 【转】Javascript面向对象编程(二):构造函数的继承