Web APi之EntityFramework【CRUD】(三)

简介:

前言

之前我们系统学习了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 > 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等操作

  View Code

 总结

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

HttpResponseException  返回异常

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

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

 




本文转自Jeffcky博客园博客,原文链接:http://www.cnblogs.com/CreateMyself/p/4820121.html,如需转载请自行联系原作者

目录
相关文章
|
5天前
|
前端开发 JavaScript API
惊呆了!学会AJAX与Fetch API,你的Python Web项目瞬间高大上!
在Web开发领域,AJAX与Fetch API是提升交互体验的关键技术。AJAX(Asynchronous JavaScript and XML)作为异步通信的先驱,通过XMLHttpRequest对象实现了局部页面更新,提升了应用流畅度。Fetch API则以更现代、简洁的方式处理HTTP请求,基于Promises提供了丰富的功能。当与Python Web框架(如Django、Flask)结合时,这两者能显著增强应用的响应速度和用户体验,使项目更加高效、高大上。
20 2
|
7天前
|
前端开发 API 开发者
从零到精通,AJAX与Fetch API让你的Python Web前后端交互无所不能!
从零到精通,AJAX与Fetch API让你的Python Web前后端交互无所不能!
21 3
|
23天前
|
安全 API 开发者
Web 开发新风尚!Python RESTful API 设计与实现,让你的接口更懂开发者心!
在当前的Web开发中,Python因能构建高效简洁的RESTful API而备受青睐,大大提升了开发效率和用户体验。本文将介绍RESTful API的基本原则及其在Python中的实现方法。以Flask为例,演示了如何通过不同的HTTP方法(如GET、POST、PUT、DELETE)来创建、读取、更新和删除用户信息。此示例还包括了基本的路由设置及操作,为开发者提供了清晰的API交互指南。
84 6
|
22天前
|
存储 JSON API
实战派教程!Python Web开发中RESTful API的设计哲学与实现技巧,一网打尽!
在数字化时代,Web API成为连接前后端及构建复杂应用的关键。RESTful API因简洁直观而广受欢迎。本文通过实战案例,介绍Python Web开发中的RESTful API设计哲学与技巧,包括使用Flask框架构建一个图书管理系统的API,涵盖资源定义、请求响应设计及实现示例。通过准确使用HTTP状态码、版本控制、错误处理及文档化等技巧,帮助你深入理解RESTful API的设计与实现。希望本文能助力你的API设计之旅。
49 3
|
23天前
|
JSON API 数据库
从零到英雄?一篇文章带你搞定Python Web开发中的RESTful API实现!
在Python的Web开发领域中,RESTful API是核心技能之一。本教程将从零开始,通过实战案例教你如何使用Flask框架搭建RESTful API。首先确保已安装Python和Flask,接着通过创建一个简单的用户管理系统,逐步实现用户信息的增删改查(CRUD)操作。我们将定义路由并处理HTTP请求,最终构建出功能完整的Web服务。无论是初学者还是有经验的开发者,都能从中受益,迈出成为Web开发高手的重要一步。
47 4
|
21天前
|
开发框架 JSON 缓存
震撼发布!Python Web开发框架下的RESTful API设计全攻略,让数据交互更自由!
在数字化浪潮推动下,RESTful API成为Web开发中不可或缺的部分。本文详细介绍了在Python环境下如何设计并实现高效、可扩展的RESTful API,涵盖框架选择、资源定义、HTTP方法应用及响应格式设计等内容,并提供了基于Flask的示例代码。此外,还讨论了版本控制、文档化、安全性和性能优化等最佳实践,帮助开发者实现更流畅的数据交互体验。
43 1
|
23天前
|
JSON API 开发者
惊!Python Web开发新纪元,RESTful API设计竟能如此性感撩人?
在这个Python Web开发的新纪元里,RESTful API的设计已经超越了简单的技术实现,成为了一种追求极致用户体验和开发者友好的艺术表达。通过优雅的URL设计、合理的HTTP状态码使用、清晰的错误处理、灵活的版本控制以及严格的安全性措施,我们能够让RESTful API变得更加“性感撩人”,为Web应用注入新的活力与魅力。
42 3
|
25天前
|
JSON API 数据格式
深度剖析!Python Web 开发中 RESTful API 的每一个细节,你不可不知的秘密!
在 Python Web 开发中,RESTful API 是构建强大应用的关键,基于 Representational State Transfer 架构风格,利用 HTTP 卞性能。通过 GET、POST、PUT 和 DELETE 方法分别实现资源的读取、创建、更新和删除操作。示例代码展示了如何使用 Flask 路由处理这些请求,并强调了状态码的正确使用,如 200 表示成功,404 表示未找到资源等。
44 5
|
5天前
|
前端开发 API 数据格式
颠覆传统!AJAX、Fetch API与Python后端,开启Web开发新篇章!
在Web开发领域,技术的快速迭代推动着应用不断进化。传统前后端交互方式已无法满足现代Web应用对高效、实时性和用户体验的需求。AJAX作为异步通信的先驱,使页面无需刷新即可更新部分内容,显著提升用户体验;尽管XML曾是其主要数据格式,但如今JSON已成为主流。Fetch API则以其简洁、灵活的特点成为AJAX的现代替代品,基于Promises的异步请求让开发更加高效。与此同时,Python后端凭借高效稳定和丰富的库支持,成为众多开发者的首选,无论是轻量级的Flask还是全功能的Django,都能为Web应用提供强大的支撑。
17 0
|
6天前
|
XML 前端开发 API
惊艳全场的秘诀!AJAX、Fetch API与Python后端,打造令人惊叹的Web应用!
惊艳全场的秘诀!AJAX、Fetch API与Python后端,打造令人惊叹的Web应用!
15 0