前言

之前我们系统学习了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();
else
return 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);
else
this.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);
else
this.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();
else
this.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();
else
foreach (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 > )
{
for (int i = ; i <= parameters.Length - ; i++)
{
var p = parameters[i] as DbParameter;
if (p == null)
throw new Exception("Not support parameter type"); commandText += i == ? " " : ", "; 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 = ; 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);
else
return 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) <= )
{
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);
}

总结

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

HttpResponseException  返回异常

HttpResponseMessage   返回信息(诸如状态码等)

HttpStatusCode       状态码枚举(如页面未找到等)

源代码下载

WebAPI之EntityFramework

Web APi之EntityFramework【CRUD】(三)的更多相关文章

  1. 在ASP.NET MVC中使用Web API和EntityFramework构建应用程序

    最近做了一个项目技术预研:在ASP.NET MVC框架中使用Web API和EntityFramework,构建一个基础的架构,并在此基础上实现基本的CRUD应用. 以下是详细的步骤. 第一步 在数据 ...

  2. MVC中使用Web API和EntityFramework

    在ASP.NET MVC中使用Web API和EntityFramework构建应用程序   最近做了一个项目技术预研:在ASP.NET MVC框架中使用Web API和EntityFramework ...

  3. ABP 教程文档 1-1 手把手引进门之 AngularJs, ASP.NET MVC, Web API 和 EntityFramework(官方教程翻译版 版本3.2.5)含学习资料

    本文是ABP官方文档翻译版,翻译基于 3.2.5 版本 转载请注明出处:http://www.cnblogs.com/yabu007/  谢谢 官方文档分四部分 一. 教程文档 二.ABP 框架 三. ...

  4. [译]ABP框架使用AngularJs,ASP.NET MVC,Web API和EntityFramework构建N层架构的SPA应用程序

    本文转自:http://www.skcode.cn/archives/281 本文演示ABP框架如何使用AngularJs,ASP.NET MVC,Web API 和EntityFramework构建 ...

  5. ABP示例程序-使用AngularJs,ASP.NET MVC,Web API和EntityFramework创建N层的单页面Web应用

    本片文章翻译自ABP在CodeProject上的一个简单示例程序,网站上的程序是用ABP之前的版本创建的,模板创建界面及工程文档有所改变,本文基于最新的模板创建.通过这个简单的示例可以对ABP有个更深 ...

  6. Web API路由与动作(三)

    本章包括三个小节  如果你输入了mvc的路由规则 这个可以粗略过一遍即可  内容说明有点繁琐 原文地址:http://www.asp.net/web-api/overview/web-api-rout ...

  7. 使用ASP.NET web API创建REST服务(三)

    本文档来源于:http://www.cnblogs.com/madyina/p/3390773.html Creating a REST service using ASP.NET Web API A ...

  8. ASP。netcore,Angular2 CRUD动画使用模板包,WEB API和EF 1.0.1

    下载Angular2ASPCORE.zip - 1 MB 介绍 在本文中,让我们看看如何创建一个ASP.NET Core CRUD web应用程序与Angular2动画使用模板包,web API和EF ...

  9. ASP。NET Core Blazor CRUD使用实体框架和Web API

    下载source code - 1.7 MB 介绍 *请查看我的Youtube视频链接来学习ASP.NET Core Blazor CRUD使用实体框架和Web API. 在本文中,我们将了解如何为A ...

随机推荐

  1. bootstrap之伪元素

    bootstrap之伪元素 参考地址:http://www.cnblogs.com/keyi/p/5943178.html http://www.runoob.com/css/css-pseudo-e ...

  2. 实现Myxls设置行高的功能(转)

    MyXLS是一个导出Excel的好工具,速度快,体积小,而且也不用担心使用Com生成Excel时资源释放的问题了.但是作者提供的代码没有设置行高 要实现这个效果,首先需要修改两个文件: 1.Row.c ...

  3. sublime 安装 插件

    从菜单 View - Show Console 或者 ctrl + ~ 快捷键,调出 console.将以下 Python 代码粘贴进去并 enter 执行,不出意外即完成安装.以下提供 ST3 和 ...

  4. es6转es5

    一.在没有IDE情况下的转换 在"我的电脑->D盘”新建个文件夹es6,文件夹里新建一个文件es6.js. 打开命令行窗口 1.先全局安装babel-cli,输入命令 npm inst ...

  5. NFSv4的引用,迁移和备份(用户手册 v0.2)

    RFC3530 定义了NFS文件系统迁移和引用的管理机制.文件系统定位功能通过fs_location属性向客户端提供文件系统的位置信息.fs_location属 性是一个包含有位置信息的列表,位置信息 ...

  6. 黑马程序员----java基础笔记下(毕向东)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 目录--- 21.字符编码 22.javaswig 事件 23.socket 网络通讯 24.网 ...

  7. php止刷新页面重复提交

    利用session来解决,首先新建一个session,并赋值,第一次提交后改变session的值,当第二次再此提交此内容时,如果不是我们的赋值,就不在处理传过来的数据.如:<?php sessi ...

  8. 【noip 2005】 采药

    题目描述 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:" ...

  9. 新手 gulp+ seajs 小demo

    首先,不说废话,它的介绍和作者就不在多说了,网上一百度一大堆: 我在这里只是来写写我这2天抽空对seajs的了解并爬过的坑,和实现的一个小demo(纯属为了实现,高手请绕道); 一.环境工具及安装 1 ...

  10. JS 的事件委托机制

    以前写上图所示的鼠标点击触发事件,一般都是用如下所示的给每一个表示列表的标签绑定一个click事件(演示用的例子的框架是React): 毫无疑问,这样是比较繁琐的,以后维护修改改个函数名什么的还不方便 ...