前沿

  园子里已有挺多博文介绍了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

 
分类: asp.net core

EFCore+Mysql仓储层建设(分页、多字段排序、部分字段更新)的更多相关文章

  1. angularjs 字段排序 多字段排序

    我们用angularjs {{}},ng-model循环绑定数组或对象的内容的时候,有时候会用到排序,有时候可能会有多个字段排序 具体要用到过滤 数据的展现,可以通过ng-repeat实现.当网页解析 ...

  2. C# List根据某一字段排序 将字段相同的排序到一起

    List<JZJLXQ_Prescription_Item> ciList = new List<JZJLXQ_Prescription_Item>(); List<JZ ...

  3. .netCore+Vue 搭建的简捷开发框架 (2)--仓储层实现和EFCore 的使用

    书接上文,继续搭建我们基于.netCore 的开发框架.首先是我们的项目分层结构. 这个分层结构,是参考张老师的分层结构,但是实际项目中,我没有去实现仓储模型.因为我使用的是EFCore ,最近也一直 ...

  4. abp(net core)+easyui+efcore实现仓储管理系统——展现层实现增删改查之列表视图(七)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  5. Oracle、MySql、SQLServer 数据分页查询

    最近简单的对oracle,mysql,sqlserver2005的数据分页查询作了研究,把各自的查询的语句贴出来供大家学习..... (一). mysql的分页查询 mysql的分页查询是最简单的,借 ...

  6. MySQL 百万级分页优化(Mysql千万级快速分页)

    以下分享一点我的经验 一般刚开始学SQL的时候,会这样写 : SELECT * FROM table ORDER BY id LIMIT 1000, 10; 但在数据达到百万级的时候,这样写会慢死 : ...

  7. 2019年7月16日 abp(net core)+easyui+efcore实现仓储管理系统——多语言(十)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  8. abp(net core)+easyui+efcore实现仓储管理系统——使用 WEBAPI实现CURD (十一)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  9. abp(net core)+easyui+efcore实现仓储管理系统——使用 WEBAPI实现CURD (十二)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

随机推荐

  1. Scrum【转】

    转载自:https://www.cnblogs.com/l2rf/p/5783726.html 灵感来自于一段冷笑话: 一天,一头猪和一只鸡在路上散步,鸡看了一下猪说,“嗨,我们合伙开一家餐馆怎么样? ...

  2. HFSS在进行仿真时端口与激励设置细则

    最近发现在使用HFSS仿真天线时候在设置端口激励求解的时候,由于端口激励面积的大小和放置方式的不通最终的求解结果也有很多不同 在进行CPW结构的天线仿真中分别尝试了waveport 和lumpedpo ...

  3. JSP、HTML页面概述

    1. 展示 <%-- 此页面为jsp页面 --%> <!-- <%-- 注释 --%> JSP注释,注释内容不会被发送至浏览器甚至不会被编译 --> <%-- ...

  4. 思维导图读PMbok第6版 - 项目整合管理(21张全讲)

    “ 3个月,800多页书,一大堆工作,复习时间不够呀?老师用思维导图解析PMP,思维导图解析PMP梳理PMbok第6版逻辑结构,帮你您全局掌握PMP知识,重点掌握PMbok难点.快速记忆PMP知识,思 ...

  5. (二叉树 递归) leetcode 889. Construct Binary Tree from Preorder and Postorder Traversal

    Return any binary tree that matches the given preorder and postorder traversals. Values in the trave ...

  6. ansible Templates

    Files和templates files和templates均用于ansible文件处理,两者的主要区别是:Files目录下的文件无需写绝对路径即可将文件传输到远程主机,templates目录下文件 ...

  7. python之路(6)迭代器和生成器

     目录 迭代器(Iterator) 生成器(Generator) 迭代器 迭代器协议:对象提供一个next方法,执行该方法要么返回下一项,要么引起一个Stopiteration异常 可迭代对象:实现了 ...

  8. 2018-2019-2 《Java程序设计》第9周学习总结

    20175319 2018-2019-2 <Java程序设计>第9周学习总结 教材学习内容总结 本周学习任务: 下载安装MySQL数据库管理系统. 教材介绍在官网下载安装Mysql服务,启 ...

  9. easyExcel导出excel的简单使用

    easyExcel导出excel的简单使用 Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定 ...

  10. <HTML> 模块

    一些元素 <q>元素 用于引用, quote 浏览器一般会负责加上双引号,但是不是所有的浏览器都会在<q>元素的内容两边加双引号. <blockquote>元素 用 ...