EFCore+Mysql倉儲層建設(分頁、多字段排序、部分字段更新)

前沿

  園子裏已有挺多博文介紹了EFCore+Mysql/MSSql如何進行使用,但實際開發不會把EF層放在Web層混合起來,需要多個項目配合結構清晰的進行分層工作,本文根據個人實踐經驗總結將各個項目進行分層,僅供想自己搭建,包含數據倉儲以及分頁多字段排序。

目錄結構

1.實體層(EF)搭建

1.1添加Nuget包

1.2添加實體

1.3構造DbContext

1.4數據遷移生成數據庫

2.倉儲層搭建

  2.1添加Nuget包

  2.2添加必要的支持IEnumerable<T>和IQueryable<T> 的OrderBy字符串支持類LinqExtensions

  2.3構造RepositoryBase<T>

  2.4添加Table文件夾,添加SysUserRepository

  2.5添加工作單元UnitOfWork

3.WebApi項目測試

  3.1注入EF

  3.2測試

4.Github項目地址

 

正文

1.實體層(EF)搭建

新建.NetCore類庫項目Entity,本人使用的是2.0的SDK

1.1添加Nuget包

PM> Install-Package Microsoft.AspNetCore.All -version 2.0.9
PM> Install-Package Pomelo.EntityFrameworkCore.MySql -version 2.0.1

1.2添加實體

父類EntityBase

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace Entity.Table
{
    public class EntityBase
    {
        /// <summary>
        /// 創建時間
        /// </summary>
        [Display(Name = "創建時間")]
        public DateTime? CreateTime { get; set; } = DateTime.Now;

        /// <summary>
        /// 創建人
        /// </summary>
        [Display(Name = "創建人")]
        [StringLength(32)]
        public string CreateUser { get; set; }

        /// <summary>
        /// 狀態0-刪除,1-正常,2-禁用,3-待審覈
        /// </summary>
        [Display(Name = "狀態0-邏輯刪除,1-正常,2-禁用,...")]
        public virtual int? Status { get; set; } = 2;

        /// <summary>
        /// 排序
        /// </summary>
        [Display(Name = "排序")]
        public int? Sort { get; set; } = 0;

        /// <summary>
        /// 備註
        /// </summary>
        [Display(Name = "備註")]
        [StringLength(200)]
        public string Remark { get; set; } = "";
    }
}

實體類SysUser

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace Entity.Table
{
    [Table("Sys_User")]
    public class SysUser : EntityBase
    {
        [Key]
        [StringLength(32)]
        public string SysUserId { get; set; }

        [Display(Name = "用戶名")]
        [Required]
        [StringLength(32)]
        public string UserName { get; set; }

        [Display(Name = "密碼")]
        [StringLength(255)]
        public string Password { get; set; }

        [Display(Name = "真實姓名")]
        [StringLength(32)]
        public string TrueName { get; set; }

        [Display(Name = "暱稱")]
        [StringLength(32)]
        public string NikeName { get; set; }

        [Display(Name = "手機號")]
        [StringLength(20)]
        public string Mobile { get; set; }

        [Display(Name = "郵箱")]
        [EmailAddress]
        [StringLength(100)]
        public string Email { get; set; }

        [Display(Name = "QQOpenid")]
        [StringLength(200)]
        public string QQ { get; set; }

        [Display(Name = "微信openid")]
        [StringLength(200)]
        public string WX { get; set; }

        [Display(Name = "頭像")]
        [StringLength(255)]
        public string Avatar { get; set; }

        [Display(Name = "性別")]
        [StringLength(1)]
        public string Sex { get; set; }

        [Display(Name = "用戶類型")]
        [StringLength(1)]
        public string UserType { get; set; }//0-前臺用戶,1-管理用戶

    }
}

1.3構造DbContext

using Entity.Table;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;

namespace Entity
{
    public class AeDbContext : DbContext
    {
        #region 構造方法
        public AeDbContext(DbContextOptions<AeDbContext> options) : base(options) { }
        public AeDbContext() { } //非注入構造方式
        #endregion

        #region 表對象
        public virtual DbSet<SysUser> SysUsers { get; set; }
        #endregion

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            if (!optionsBuilder.IsConfigured)
            {
                //重點:數據遷移或者直接New AeDbContext時候用到的鏈接字符串獲取方式
                var builder = new ConfigurationBuilder()
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                var configuration = builder.Build();
                string connectionString = configuration.GetConnectionString("SQLConnection");
                optionsBuilder.UseMySql(connectionString);
            }
        }
    }
}

在這有重寫OnConfiguring方法,如果沒有構造數據庫鏈接字符串的話則到appsettings.json中去取,注意將appsettings.json文件始終複製

 

appsettings.json

{
  "ConnectionStrings": {
    "SQLConnection": "server=127.0.0.1;database=eftest;userid=root;pwd=123456;port=3306;sslmode=none;"
  },
  "server.urls": "http://localhost:5001" //監聽端口配置,可多個
}

1.4數據遷移生成數據庫

打開PM選擇默認項目Entity

 輸入

PM> Add-Migration init

若提示The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'E:\VS項目\EFTest\Entity\bin\Debug\netcoreapp2.0\appsettings.json'.

則爲沒檢測到appsettings.json,需要文件更改屬性爲複製

提示後進行更新數據庫,如下爲更新成功。

PM> update-database

 

 最後Entity項目內容如下

 

2.倉儲層搭建

新建.NetCore類庫項目Repository並引用項目Entity

2.1添加Nuget包

PM> Install-Package Microsoft.EntityFrameworkCore -version 2.0.3
PM> Install-Package LinqKit.Microsoft.EntityFrameworkCore -version 1.1.15

 

2.2添加必要的支持IEnumerable<T>和IQueryable<T> 的OrderBy字符串支持類LinqExtensions

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.Generic;

namespace Repository
{
    internal static class LinqExtensions {
        private static PropertyInfo GetPropertyInfo(Type objType, string name) {
            var properties = objType.GetProperties();
            var matchedProperty = properties.FirstOrDefault(p => p.Name == name);
            if (matchedProperty == null) {
                throw new ArgumentException("name");
            }

            return matchedProperty;
        }
        private static LambdaExpression GetOrderExpression(Type objType, PropertyInfo pi) {
            var paramExpr = Expression.Parameter(objType);
            var propAccess = Expression.PropertyOrField(paramExpr, pi.Name);
            var expr = Expression.Lambda(propAccess, paramExpr);
            return expr;
        }
        /// <summary>
        /// 多個OrderBy用逗號隔開,屬性前面帶-號表示反序排序,exp:"name,-createtime"
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IEnumerable<T> OrderByBatch<T>(this IEnumerable<T> query, string name) {
            var index = 0;
            var a = name.Split(',');
            foreach (var item in a) {
                var m = index++ > 0 ? "ThenBy" : "OrderBy";
                if (item.StartsWith("-")) {
                    m += "Descending";
                    name = item.Substring(1);
                } else {
                    name = item;
                }
                name = name.Trim();

                var propInfo = GetPropertyInfo(typeof(T), name);
                var expr = GetOrderExpression(typeof(T), propInfo);
                var method = typeof(Enumerable).GetMethods().FirstOrDefault(mt => mt.Name == m && mt.GetParameters().Length == 2);
                var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);
                query = (IEnumerable<T>)genericMethod.Invoke(null, new object[] { query, expr.Compile() });
            }
            return query;
        }

        /// <summary>
        /// 多個OrderBy用逗號隔開,屬性前面帶-號表示反序排序,exp:"name,-createtime"
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IQueryable<T> OrderByBatch<T>(this IQueryable<T> query, string name)
        {
            var index = 0;
            var a = name.Split(',');
            foreach (var item in a)
            {
                var m = index++ > 0 ? "ThenBy" : "OrderBy";
                if (item.StartsWith("-"))
                {
                    m += "Descending";
                    name = item.Substring(1);
                }
                else
                {
                    name = item;
                }
                name = name.Trim();

                var propInfo = GetPropertyInfo(typeof(T), name);
                var expr = GetOrderExpression(typeof(T), propInfo);
                var method = typeof(Queryable).GetMethods().FirstOrDefault(mt => mt.Name == m && mt.GetParameters().Length == 2);
                var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);
                query = (IQueryable<T>)genericMethod.Invoke(null, new object[] { query, expr });
            }
            return query;
        }
        
        /// <summary>
        /// 正序排序單個
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string name) {
            var propInfo = GetPropertyInfo(typeof(T), name);
            var expr = GetOrderExpression(typeof(T), propInfo);

            var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
            var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);
            return (IQueryable<T>)genericMethod.Invoke(null, new object[] { query, expr });
        }
        /// <summary>
        /// 正序排序單個(非首個)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IQueryable<T> ThenBy<T>(this IQueryable<T> query, string name)
        {
            var propInfo = GetPropertyInfo(typeof(T), name);
            var expr = GetOrderExpression(typeof(T), propInfo);

            var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "ThenBy" && m.GetParameters().Length == 2);
            var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);
            return (IQueryable<T>)genericMethod.Invoke(null, new object[] { query, expr });
        }
        /// <summary>
        /// 反序排序單個
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string name)
        {
            var propInfo = GetPropertyInfo(typeof(T), name);
            var expr = GetOrderExpression(typeof(T), propInfo);
            var metMethods = typeof(Queryable).GetMethods();
            var method = metMethods.FirstOrDefault(m => m.Name == "OrderByDescending" && m.GetParameters().Length == 2);
            var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);
            return (IQueryable<T>)genericMethod.Invoke(null, new object[] { query, expr });
        }
        /// <summary>
        /// 反序排序單個(非首個)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IQueryable<T> ThenByDescending<T>(this IQueryable<T> query, string name)
        {
            var propInfo = GetPropertyInfo(typeof(T), name);
            var expr = GetOrderExpression(typeof(T), propInfo);
            var metMethods = typeof(Queryable).GetMethods();
            var method = metMethods.FirstOrDefault(m => m.Name == "ThenByDescending" && m.GetParameters().Length == 2);
            var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);
            return (IQueryable<T>)genericMethod.Invoke(null, new object[] { query, expr });
        }
    }
}

以及分頁支持類PageData<T>

using System;
using System.Collections.Generic;
using System.Text;

namespace Repository
{
    public class PageData<T>
    {
        public List<T> Rows { get; set; }
        public long Totals { get; set; }
    }
}

2.3構造RepositoryBase<T>

using Entity;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Infrastructure;
using System.IO;
using Entity.Table;

namespace Repository
{
    public class RepositoryBase<T> where T : EntityBase
    {
        private readonly DbSet<T> _dbSet;
        public AeDbContext DbContext { get; } = null;
        public RepositoryBase(AeDbContext context)
        {
            DbContext = context;
            _dbSet = DbContext.Set<T>();
        }
        public DatabaseFacade Database => DbContext.Database;
        public IQueryable<T> Entities => _dbSet.AsQueryable().AsNoTracking();
        public int SaveChanges()
        {
            return DbContext.SaveChanges();
        }
        public async Task<int> SaveChangesAsync()
        {
            return await DbContext.SaveChangesAsync();
        }
        public bool Any(Expression<Func<T, bool>> whereLambd)
        {
            return _dbSet.Where(whereLambd).Any();
        }
        public void Disposed()
        {
            throw new Exception("不允許在這裏釋放上下文,請在UnitOfWork中操作");
            //DbContext.Dispose();
        }

        #region 插入數據
        public bool Insert(T entity, bool isSaveChange = true)
        {
            _dbSet.Add(entity);
            if (isSaveChange)
            {
                return SaveChanges() > 0;
            }
            return false;
        }
        public async Task<bool> InsertAsync(T entity, bool isSaveChange = true)
        {
            _dbSet.Add(entity);
            if (isSaveChange)
            {
                return await SaveChangesAsync() > 0;
            }
            return false;
        }
        public bool Insert(List<T> entitys, bool isSaveChange = true)
        {
            _dbSet.AddRange(entitys);
            if (isSaveChange)
            {
                return SaveChanges() > 0;
            }
            return false;
        }
        public async Task<bool> InsertAsync(List<T> entitys, bool isSaveChange = true)
        {
            _dbSet.AddRange(entitys);
            if (isSaveChange)
            {
                return await SaveChangesAsync() > 0;
            }
            return false;
        }
        #endregion

        #region 刪除
        public bool Delete(T entity, bool isSaveChange = true)
        {
            _dbSet.Attach(entity);
            _dbSet.Remove(entity);
            return isSaveChange ? SaveChanges() > 0 : false;
        }
        public bool Delete(List<T> entitys, bool isSaveChange = true)
        {
            entitys.ForEach(entity =>
            {
                _dbSet.Attach(entity);
                _dbSet.Remove(entity);
            });
            return isSaveChange ? SaveChanges() > 0 : false;
        }

        public virtual async Task<bool> DeleteAsync(T entity, bool isSaveChange = true)
        {

            _dbSet.Attach(entity);
            _dbSet.Remove(entity);
            return isSaveChange ? await SaveChangesAsync() > 0 : false;
        }
        public virtual async Task<bool> DeleteAsync(List<T> entitys, bool isSaveChange = true)
        {
            entitys.ForEach(entity =>
            {
                _dbSet.Attach(entity);
                _dbSet.Remove(entity);
            });
            return isSaveChange ? await SaveChangesAsync() > 0 : false;
        }
        #endregion

        #region 更新數據
        public bool Update(T entity, bool isSaveChange = true, List<string> updatePropertyList = null, bool modified = true)
        {
            if (entity == null)
            {
                return false;
            }
            _dbSet.Attach(entity);
            var entry = DbContext.Entry(entity);
            if (updatePropertyList == null)
            {
                entry.State = EntityState.Modified;//全字段更新
            }
            else
            {
                if (modified)
                {
                    updatePropertyList.ForEach(c => {
                        entry.Property(c).IsModified = true; //部分字段更新的寫法
                    });
                }
                else
                {
                    entry.State = EntityState.Modified;//全字段更新
                    updatePropertyList.ForEach(c => {
                        entry.Property(c).IsModified = false; //部分字段不更新的寫法
                    });
                }
            }
            if (isSaveChange)
            {
                return SaveChanges() > 0;
            }
            return false;
        }
        public bool Update(List<T> entitys, bool isSaveChange = true)
        {
            if (entitys == null || entitys.Count == 0)
            {
                return false;
            }
            entitys.ForEach(c => {
                Update(c, false);
            });
            if (isSaveChange)
            {
                return SaveChanges() > 0;
            }
            return false;
        }
        public async Task<bool> UpdateAsync(T entity, bool isSaveChange = true, List<string> updatePropertyList = null, bool modified = true)
        {
            if (entity == null)
            {
                return false;
            }
            _dbSet.Attach(entity);
            var entry = DbContext.Entry<T>(entity);
            if (updatePropertyList == null)
            {
                entry.State = EntityState.Modified;//全字段更新
            }
            else
            {
                if (modified)
                {
                    updatePropertyList.ForEach(c => {
                        entry.Property(c).IsModified = true; //部分字段更新的寫法
                    });
                }
                else
                {
                    entry.State = EntityState.Modified;//全字段更新
                    updatePropertyList.ForEach(c => {
                        entry.Property(c).IsModified = false; //部分字段不更新的寫法
                    });
                }
            }
            if (isSaveChange)
            {
                return await SaveChangesAsync() > 0;
            }
            return false;
        }
        public async Task<bool> UpdateAsync(List<T> entitys, bool isSaveChange = true)
        {
            if (entitys == null || entitys.Count == 0)
            {
                return false;
            }
            entitys.ForEach(c => {
                _dbSet.Attach(c);
                DbContext.Entry<T>(c).State = EntityState.Modified;
            });
            if (isSaveChange)
            {
                return await SaveChangesAsync() > 0;
            }
            return false;
        }
        #endregion

        #region 查找
        public long Count(Expression<Func<T, bool>> predicate = null)
        {
            if (predicate == null)
            {
                predicate = c => true;
            }
            return _dbSet.LongCount(predicate);
        }
        public async Task<long> CountAsync(Expression<Func<T, bool>> predicate = null)
        {
            if (predicate == null)
            {
                predicate = c => true;
            }
            return await _dbSet.LongCountAsync(predicate);
        }
        public T Get(object id)
        {
            if (id == null)
            {
                return default(T);
            }
            return _dbSet.Find(id);
        }
        public T Get(Expression<Func<T, bool>> predicate = null, bool isNoTracking = true)
        {
            var data = isNoTracking ? _dbSet.Where(predicate).AsNoTracking() : _dbSet.Where(predicate);
            return data.FirstOrDefault();
        }
        public async Task<T> GetAsync(object id)
        {
            if (id == null)
            {
                return default(T);
            }
            return await _dbSet.FindAsync(id);
        }
        public async Task<T> GetAsync(Expression<Func<T, bool>> predicate = null, bool isNoTracking = true)
        {
            var data = isNoTracking ? _dbSet.Where(predicate).AsNoTracking() : _dbSet.Where(predicate);
            return await data.FirstOrDefaultAsync();
        }
        public async Task<List<T>> GetListAsync(Expression<Func<T, bool>> predicate = null, string ordering = "", bool isNoTracking = true)
        {
            var data = isNoTracking ? _dbSet.Where(predicate).AsNoTracking() : _dbSet.Where(predicate);
            if (!string.IsNullOrEmpty(ordering))
            {
                data = data.OrderByBatch(ordering);
            }
            return await data.ToListAsync();
        }
        public List<T> GetList(Expression<Func<T, bool>> predicate = null, string ordering = "", bool isNoTracking = true)
        {
            var data = isNoTracking ? _dbSet.Where(predicate).AsNoTracking() : _dbSet.Where(predicate);
            if (!string.IsNullOrEmpty(ordering))
            {
                data = data.OrderByBatch(ordering);
            }
            return data.ToList();
        }
        public async Task<IQueryable<T>> LoadAsync(Expression<Func<T, bool>> predicate = null, bool isNoTracking = true)
        {
            if (predicate == null)
            {
                predicate = c => true;
            }
            return await Task.Run(() => isNoTracking ? _dbSet.Where(predicate).AsNoTracking() : _dbSet.Where(predicate));
        }
        public IQueryable<T> Load(Expression<Func<T, bool>> predicate = null, bool isNoTracking = true)
        {
            if (predicate == null)
            {
                predicate = c => true;
            }
            return isNoTracking ? _dbSet.Where(predicate).AsNoTracking() : _dbSet.Where(predicate);
        }
        #region 分頁查找
        /// <summary>
        /// 分頁查詢異步
        /// </summary>
        /// <param name="whereLambda">查詢添加(可有,可無)</param>
        /// <param name="ordering">排序條件(一定要有)</param>
        /// <param name="pageIndex">當前頁碼</param>
        /// <param name="pageSize">每頁大小</param>
        /// <param name="isOrder">排序正反</param>
        /// <returns></returns>
        public async Task<PageData<T>> GetPageAsync<TKey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, TKey>> orderBy, int pageIndex, int pageSize, bool isOrder = true, bool isNoTracking = true)
        {
            IQueryable<T> data = isOrder ?
                _dbSet.OrderBy(orderBy) :
                _dbSet.OrderByDescending(orderBy);

            if (whereLambda != null)
            {
                data = isNoTracking ? data.Where(whereLambda).AsNoTracking() : data.Where(whereLambda);
            }
            PageData<T> pageData = new PageData<T>
            {
                Totals = await data.CountAsync(),
                Rows = await data.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync()
            };
            return pageData;
        }

        /// <summary>
        /// 分頁查詢異步
        /// </summary>
        /// <param name="whereLambda">查詢添加(可有,可無)</param>
        /// <param name="ordering">排序條件(一定要有,多個用逗號隔開,倒序開頭用-號)</param>
        /// <param name="pageIndex">當前頁碼</param>
        /// <param name="pageSize">每頁大小</param>
        /// <returns></returns>
        public async Task<PageData<T>> GetPageAsync(Expression<Func<T, bool>> whereLambda, string ordering, int pageIndex, int pageSize, bool isNoTracking = true)
        {
            // 分頁 一定注意: Skip 之前一定要 OrderBy
            if (string.IsNullOrEmpty(ordering))
            {
                ordering = nameof(T) + "Id";//默認以Id排序
            }
            var data = _dbSet.OrderByBatch(ordering);
            if (whereLambda != null)
            {
                data = isNoTracking ? data.Where(whereLambda).AsNoTracking() : data.Where(whereLambda);
            }
            //查看生成的sql,找到大數據下分頁巨慢原因爲order by 耗時
            //var sql = data.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToSql();
            //File.WriteAllText(@"D:\sql.txt",sql);
            PageData<T> pageData = new PageData<T>
            {
                Totals = await data.CountAsync(),
                Rows = await data.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync()
            };
            return pageData;
        }

        /// <summary>
        /// 分頁查詢
        /// </summary>
        /// <param name="whereLambda">查詢添加(可有,可無)</param>
        /// <param name="ordering">排序條件(一定要有,多個用逗號隔開,倒序開頭用-號)</param>
        /// <param name="pageIndex">當前頁碼</param>
        /// <param name="pageSize">每頁大小</param>
        /// <returns></returns>
        public PageData<T> GetPage(Expression<Func<T, bool>> whereLambda, string ordering, int pageIndex, int pageSize, bool isNoTracking = true)
        {
            // 分頁 一定注意: Skip 之前一定要 OrderBy
            if (string.IsNullOrEmpty(ordering))
            {
                ordering = nameof(T) + "Id";//默認以Id排序
            }
            var data = _dbSet.OrderByBatch(ordering);
            if (whereLambda != null)
            {
                data = isNoTracking ? data.Where(whereLambda).AsNoTracking() : data.Where(whereLambda);
            }
            PageData<T> pageData = new PageData<T>
            {
                Totals = data.Count(),
                Rows = data.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList()
            };
            return pageData;
        }
        #endregion
        #endregion
    }
}

2.4添加Table文件夾,添加SysUserRepository

using Entity;
using Entity.Table;
using System;
using System.Collections.Generic;
using System.Text;

namespace Repository.Table
{
    public class SysUserRepository : RepositoryBase<SysUser>
    {
        public SysUserRepository(AeDbContext context) : base(context)
        {
        }
    }
}

2.5添加工作單元UnitOfWork

using Entity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Repository.Table;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Repository
{
    public class UnitOfWork : IDisposable
    {
        public static UnitOfWork Instance = new UnitOfWork(new AeDbContext());
        public AeDbContext DbContext { get; set; } = null;
        public UnitOfWork(AeDbContext dbContext)
        {
            DbContext = dbContext;
        }

        #region 字段
        private SysUserRepository _SysUserRepository = null;
        #endregion

        #region 操作類屬性
        public SysUserRepository SysUserRepository => _SysUserRepository ?? (_SysUserRepository = new SysUserRepository(DbContext));
        #endregion

        #region 倉儲操作(提交事務保存SaveChanges(),回滾RollBackChanges(),釋放資源Dispose())
        /// <summary>
        /// 保存
        /// </summary>
        public int SaveChanges()
        {
            return DbContext.SaveChanges();
        }
        public async Task<int> SaveChangesAsync()
        {
            return await DbContext.SaveChangesAsync();
        }
        /// <summary>
        /// 回滾
        /// </summary>
        public void RollBackChanges()
        {
            var items = DbContext.ChangeTracker.Entries().ToList();
            items.ForEach(o => o.State = EntityState.Unchanged);
        }
        /// <summary>
        /// 釋放資源
        /// </summary>
        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    DbContext.Dispose();//隨着工作單元的銷燬而銷燬
                }
            }
            this.disposed = true;
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        public IDbContextTransaction BeginTransaction()
        {
            var scope = DbContext.Database.BeginTransaction();
            return scope;
        }
        #endregion
    }
}

這樣倉儲層就構造完成了,篇幅已經很長了,Service層就先不介紹了。

3.WebApi項目測試

新建.NetCore的項目的Web應用程序ApiTest,選擇webapi方式,並引用Entity和Repository項目

3.1注入EF

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddDbContext<AeDbContext>(options => options.UseMySql(Configuration.GetConnectionString("SQLConnection")));
       services.AddTransient(typeof(UnitOfWork));//注入工作單元 }

3.2測試

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Repository;

namespace ApiTest.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        UnitOfWork _unitOfWork;
        public ValuesController(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }
        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            var adminModel = _unitOfWork.SysUserRepository.Get("admin");
            if(adminModel == null)
            {
                adminModel = new Entity.Table.SysUser()
                {
                    SysUserId = "admin",
                    UserName = "admin",
                    Password = "123456",
                    UserType = "1",
                    CreateTime = DateTime.Now,
                    Status = 1,
                    Sort = 0
                };
                _unitOfWork.SysUserRepository.Insert(adminModel);
            }
            return new List<string> { adminModel.UserName , adminModel.Password };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

測試結果:

 

倉儲分頁查詢 測試

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Entity.Table;
using LinqKit;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Repository;

namespace ApiTest.Controllers
{
    [Produces("application/json")]
    [Route("api/[controller]")]
    public class QueryPageController : Controller
    {
        UnitOfWork _unitOfWork;
        public QueryPageController(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }
        /// <summary>
        /// 分頁測試
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> Get(string userName,int? Status,string NikeName)
        {
            var userCount = _unitOfWork.SysUserRepository.Count();
            if(userCount < 100)
            {
                await CreateUser(100);
            }
            //獲取分頁數據方式1
            //獲取用戶名包含user的排序根據Sort正序,CreateTime倒序排序的第1頁的20條數據
            var pageModel = await _unitOfWork.SysUserRepository.GetPageAsync(o => o.UserName.Contains("user") && o.Status == 1, "Sort,-CreateTime", 1, 20);

            //獲取分頁數據方式2
            //使用PredicateBuilder獲取分頁數據方式支持篩選
            var predicate = PredicateBuilder.New<SysUser>(true);//查詢條件,推薦後臺使用這種方式靈活篩選
            #region 添加條件查詢
            if (!string.IsNullOrEmpty(userName))
            {
                predicate = predicate.And(i => i.UserName.Contains(userName));
            }
            if (Status != null)
            {
                predicate = predicate.And(i => i.Status.Equals(Status));
            }
            if (!string.IsNullOrEmpty(NikeName))
            {
                predicate = predicate.And(i => i.NikeName.Equals(NikeName));
            }
            #endregion
            var pageModel1 = await _unitOfWork.SysUserRepository.GetPageAsync(predicate, "Sort,-CreateTime", 1, 20);
            return Json(new { pageModel, pageModel1 });
        }
        /// <summary>
        /// 構造數據
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public async Task<bool> CreateUser(int count = 1)
        {
            List<SysUser> inserUsers = new List<SysUser>();
            for (int i = 0; i < count; i++)
            {
                inserUsers.Add(new SysUser
                {
                    SysUserId = Guid.NewGuid().ToString("N"),
                    UserName = $"user{i}",
                    Password = "123456",
                    UserType = "0",
                    CreateTime = DateTime.Now,
                    Status = 1,
                    Sort = 0
                });
            }
            return await _unitOfWork.SysUserRepository.InsertAsync(inserUsers);
        }

    }
}

結果:

 

4.Github項目地址

最後附上github源碼:https://github.com/atorzhang/EFTest

 注:原創,轉載請註明出處,原文地址:https://www.cnblogs.com/jomzhang/p/10245077.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章