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

书接上文,继续搭建我们基于.netCore 的开发框架。首先是我们的项目分层结构。

.netCore+Vue 搭建的简捷开发框架 (2)--仓储层实现和EFCore 的使用_第1张图片

 

这个分层结构,是参考张老师的分层结构,但是实际项目中,我没有去实现仓储模型。因为我使用的是EFCore ,最近也一直在想,EFCore 在我们的架构体系中到底扮演着什么样的角色??

当然,实现仓储层,也有他的好处,如果真的以后要更换ORM框架的时候,不用去更改服务层逻辑,不用直接在仓储里面做更改就可以了。但是对于小项目,可能运行个十年都不会换数据库,不会换ORM的项目,仓储层的意义在哪?

希望对此有自己想法的朋友一起讨论。在本系列里,我将保留仓储层。

上面的分层结构,很容易就搭建好了,但是基于.NetCore 的项目,可能最主要的一点就是如何利用好DI,怎么来实现依赖注入。

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

依照上图中的依赖关系,我们以此构建自己相应层级中的内容。

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

分别在IRepository和Repository项目下,新建Base文件夹,并分别建立IBaseRepository和BaseRepository

具体代码如下:

IBaseRepository.cs:

 1 using Sincere.Core.Model;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Data;
 5 using System.Data.SqlClient;
 6 using System.Linq.Expressions;
 7 using System.Text;
 8 using System.Threading.Tasks;
 9 
10 namespace Sincere.Core.IRepository.Base
11 {
12     public interface IBaseRepository where TEntity : class
13     {
14         Task<int> Execute(string sql, List parms, CommandType cmdType = CommandType.Text);
15         Task> Query(string sql, List parms, CommandType cmdType = CommandType.Text);
16         Task<bool> Insert(TEntity model);
17         Task<bool> InsertRange(List datas);
18 
19         Task<int> Del(TEntity model);
20 
21         Task<int> DelBy(Expressionbool>> delWhere);
22 
23         Task<int> Modify(TEntity model);
24 
25         Task<int> Modify(TEntity model, params string[] propertyNames);
26 
27         Task<int> ModifyBy(TEntity model, Expressionbool>> whereLambda, params string[] modifiedPropertyNames);
28 
29         Task> GetList();
30 
31         Task> GetListBy(Expressionbool>> whereLambda);
32 
33         Task GetModelById(Expressionbool>> whereLambda);
34 
35         Task> GetListBy(Expressionbool>> whereLambda, Expression> orderLambda, bool isAsc = true);
36 
37         Task> GetListBy(int top, Expressionbool>> whereLambda, Expression> orderLambda, bool isAsc = true);
38 
39         Task> GetListBy(Expressionbool>> whereLambda, Expression> orderLambda1, Expression> orderLambda2, bool isAsc1 = true, bool isAsc2 = true);
40 
41         Task> GetListBy(int top, Expressionbool>> whereLambda, Expression> orderLambda1, Expression> orderLambda2, bool isAsc1 = true, bool isAsc2 = true);
42 
43         Task> GetPagedList(int pageIndex, int pageSize, Expressionbool>> whereLambda, Expression> orderByLambda, bool isAsc = true);
44 
45         Task> GetPagedList(Expressionbool>> whereLambda, Expression> orderByLambda, bool isAsc = true, int pageIndex = 1, int pageSize = 20);
46 
47         void RollBackChanges();
48 
49     }
50 }
View Code

BaseRepository.cs:

  1 using Microsoft.EntityFrameworkCore;
  2 using Sincere.Core.IRepository.Base;
  3 using Sincere.Core.Model;
  4 using Sincere.Core.Model.Models;
  5 using System;
  6 using System.Collections.Generic;
  7 using System.Data;
  8 using System.Data.SqlClient;
  9 using System.Linq;
 10 using System.Linq.Expressions;
 11 using System.Reflection;
 12 using System.Text;
 13 using System.Threading.Tasks;
 14 
 15 namespace Sincere.Core.Repository.Base
 16 {
 17     public class BaseRepository : IBaseRepository where TEntity : class, new()
 18     {
 19         private BaseCoreContext _db;
 20         private readonly DbSet _dbSet;
 21 
 22         internal BaseCoreContext Db
 23         {
 24             get { return _db; }
 25             private set { _db = value; }
 26         }
 27         public BaseRepository(IBaseContext mydbcontext)
 28         {
 29             this._db = mydbcontext as BaseCoreContext;
 30             this._dbSet = _db.Set();
 31         }
 32 
 33         #region INSERT
 34 
 35         /// 
 36         /// 新增 实体
 37         /// 
 38         /// 
 39         /// 
 40         //public async Task Insert(TEntity model, bool isSaveChanges = false)
 41         public async Task<bool> Insert(TEntity model)
 42         {
 43             _db.Set().Add(model);
 44             //if (isSaveChanges)
 45             //{
 46             return await _db.SaveChangesAsync() > 0;
 47             //}
 48             //else
 49             //{
 50             //    return false;
 51             //}
 52 
 53         }
 54 
 55         /// 
 56         /// 普通批量插入
 57         /// 
 58         /// 
 59         public async Task<bool> InsertRange(List datas)
 60         {
 61             await _db.Set().AddRangeAsync(datas);
 62             return await _db.SaveChangesAsync() == datas.Count;
 63         }
 64 
 65         #endregion INSERT
 66 
 67         #region Delete
 68 
 69         #region 2.0 根据id删除 +  int Del(T model)
 70         /// 
 71         /// 2.0 根据id删除
 72         /// 
 73         /// 必须包含要删除id的对象
 74         /// 
 75         public async Task<int> Del(TEntity model)
 76         {
 77             _db.Set().Attach(model);
 78             _db.Set().Remove(model);
 79             return await _db.SaveChangesAsync();
 80         }
 81         #endregion
 82 
 83         #region 2.1 根据条件删除 + int DelBy(Expression> delWhere)
 84         /// 
 85         /// 2.1 根据条件删除
 86         /// 
 87         /// 
 88         /// 返回受影响的行数
 89         public async Task<int> DelBy(Expressionbool>> delWhere)
 90         {
 91             //2.1.1 查询要删除的数据
 92             List listDeleting = _db.Set().Where(delWhere).ToList();
 93             //2.1.2 将要删除的数据 用删除方法添加到 EF 容器中
 94             listDeleting.ForEach(u =>
 95             {
 96                 _db.Set().Attach(u);  //先附加到EF 容器
 97                 _db.Set().Remove(u); //标识为删除状态
 98             });
 99             //2.1.3 一次性生成sql语句 到数据库执行删除
100             return await _db.SaveChangesAsync();
101         }
102         #endregion
103 
104 
105         #endregion
106 
107         #region UPDATE
108 
109         #region 3.0 修改实体 +  int Modify(T model)
110         /// 
111         /// 修改实体
112         /// 
113         /// 
114         /// 
115         public async Task<int> Modify(TEntity model)
116         {
117             //EntityEntry entry = _db.Entry(model);
118             _db.Set().Update(model);
119             return await _db.SaveChangesAsync();
120         }
121         #endregion
122 
123         #region 3.1 修改实体,可修改指定属性 + int Modify(T model, params string[] propertyNames)
124         /// 
125         /// 3.1 修改实体,可修改指定属性
126         /// 
127         /// 
128         /// 
129         /// 
130         public async Task<int> Modify(TEntity model, params string[] propertyNames)
131         {
132             //3.1.1 将对象添加到EF中
133             EntityEntry entry = _db.Entry(model);
134             //3.1.2 先设置对象的包装状态为 Unchanged
135             entry.State = EntityState.Unchanged;
136             //3.1.3 循环被修改的属性名数组
137             foreach (string propertyName in propertyNames)
138             {
139                 //将每个被修改的属性的状态设置为已修改状态;这样在后面生成的修改语句时,就只为标识为已修改的属性更新
140                 entry.Property(propertyName).IsModified = true;
141             }
142             return await _db.SaveChangesAsync();
143         }
144         #endregion
145 
146         #region 3.2 批量修改 + int ModifyBy(T model, Expression> whereLambda, params string[] modifiedPropertyNames)
147         /// 
148         /// 3.2 批量修改
149         /// 
150         /// 
151         /// 
152         /// 
153         /// 
154         public async Task<int> ModifyBy(TEntity model, Expressionbool>> whereLambda, params string[] modifiedPropertyNames)
155         {
156             //3.2.1 查询要修改的数据
157             List listModifing = _db.Set().Where(whereLambda).ToList();
158             //3.2.2 获取实体类类型对象
159             Type t = typeof(TEntity);
160             //3.2.3 获取实体类所有的公共属性
161             List propertyInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
162             //3.2.4 创建实体属性字典集合
163             Dictionary<string, PropertyInfo> dicPropertys = new Dictionary<string, PropertyInfo>();
164             //3.2.5 将实体属性中要修改的属性名 添加到字典集合中  键:属性名  值:属性对象
165             propertyInfos.ForEach(p =>
166             {
167                 if (modifiedPropertyNames.Contains(p.Name))
168                 {
169                     dicPropertys.Add(p.Name, p);
170                 }
171             });
172             //3.2.6 循环要修改的属性名
173             foreach (string propertyName in modifiedPropertyNames)
174             {
175                 //判断要修改的属性名是否在实体类的属性集合中存在
176                 if (dicPropertys.ContainsKey(propertyName))
177                 {
178                     //如果存在,则取出要修改的属性对象
179                     PropertyInfo proInfo = dicPropertys[propertyName];
180                     //取出要修改的值
181                     object newValue = proInfo.GetValue(model, null);
182                     //批量设置要修改对象的属性
183                     foreach (TEntity item in listModifing)
184                     {
185                         //为要修改的对象的要修改的属性设置新的值
186                         proInfo.SetValue(item, newValue, null);
187                     }
188                 }
189             }
190             //一次性生成sql语句 到数据库执行
191             return await _db.SaveChangesAsync();
192         }
193         #endregion
194 
195 
196         #endregion UPDATE
197 
198         #region SELECT
199 
200         #region  5.0 根据条件查询 + List GetListBy(Expression> whereLambda)
201         /// 
202         /// 5.0 根据条件查询
203         /// 
204         /// 
205         /// 
206         public async Task> GetListBy(Expressionbool>> whereLambda)
207         {
208             return await _db.Set().Where(whereLambda).AsNoTracking().ToListAsync();
209         }
210 
211         public async Task GetModelById(Expressionbool>> whereLambda)
212         {
213             return await _db.Set().Where(whereLambda).AsNoTracking().FirstOrDefaultAsync();
214         }
215         public async Task> GetList()
216         {
217             return await _db.Set().AsNoTracking().ToListAsync();
218         }
219         #endregion
220 
221         #region 5.1 根据条件查询,并排序 +  List GetListBy(Expression> whereLambda, Expression> orderLambda, bool isAsc = true)
222         /// 
223         /// 5.1 根据条件查询,并排序
224         /// 
225         /// 
226         /// 
227         /// 
228         /// 
229         /// 
230         public async Task> GetListBy(Expressionbool>> whereLambda, Expression> orderLambda, bool isAsc = true)
231         {
232             if (isAsc)
233             {
234                 return await _db.Set().Where(whereLambda).OrderBy(orderLambda).AsNoTracking().ToListAsync();
235             }
236             else
237             {
238                 return await _db.Set().Where(whereLambda).OrderByDescending(orderLambda).AsNoTracking().ToListAsync();
239             }
240         }
241         #endregion
242 
243         #region 5.2 根据条件查询Top多少个,并排序 + List GetListBy(int top, Expression> whereLambda, Expression> orderLambda, bool isAsc = true)
244         /// 
245         /// 5.2 根据条件查询Top多少个,并排序
246         /// 
247         /// 
248         /// 
249         /// 
250         /// 
251         /// 
252         /// 
253         public async Task> GetListBy(int top, Expressionbool>> whereLambda, Expression> orderLambda, bool isAsc = true)
254         {
255             if (isAsc)
256             {
257                 return await _db.Set().Where(whereLambda).OrderBy(orderLambda).Take(top).AsNoTracking().ToListAsync();
258             }
259             else
260             {
261                 return await _db.Set().Where(whereLambda).OrderByDescending(orderLambda).Take(top).AsNoTracking().ToListAsync();
262             }
263         }
264         #endregion
265 
266         #region  5.3 根据条件排序查询  双排序 + List GetListBy(Expression> whereLambda, Expression> orderLambda1, Expression> orderLambda2, bool isAsc1 = true, bool isAsc2 = true)
267         /// 
268         /// 5.3 根据条件排序查询  双排序
269         /// 
270         /// 
271         /// 
272         /// 
273         /// 
274         /// 
275         /// 
276         /// 
277         /// 
278         public async Task> GetListBy(Expressionbool>> whereLambda, Expression> orderLambda1, Expression> orderLambda2, bool isAsc1 = true, bool isAsc2 = true)
279         {
280             if (isAsc1)
281             {
282                 if (isAsc2)
283                 {
284                     return await _db.Set().Where(whereLambda).OrderBy(orderLambda1).ThenBy(orderLambda2).AsNoTracking().ToListAsync();
285                 }
286                 else
287                 {
288                     return await _db.Set().Where(whereLambda).OrderBy(orderLambda1).ThenByDescending(orderLambda2).AsNoTracking().ToListAsync();
289                 }
290             }
291             else
292             {
293                 if (isAsc2)
294                 {
295                     return await _db.Set().Where(whereLambda).OrderByDescending(orderLambda1).ThenBy(orderLambda2).AsNoTracking().ToListAsync();
296                 }
297                 else
298                 {
299                     return await _db.Set().Where(whereLambda).OrderByDescending(orderLambda1).ThenByDescending(orderLambda2).AsNoTracking().ToListAsync();
300                 }
301             }
302         }
303         #endregion
304 
305         #region 5.3 根据条件排序查询Top个数  双排序 + List GetListBy(int top, Expression> whereLambda, System.Linq.Expressions.Expression> orderLambda1, Expression> orderLambda2, bool isAsc1 = true, bool isAsc2 = true)
306         /// 
307         ///  5.3 根据条件排序查询Top个数  双排序
308         /// 
309         /// 
310         /// 
311         /// 
312         /// 
313         /// 
314         /// 
315         /// 
316         /// 
317         /// 
318         public async Task> GetListBy(int top, Expressionbool>> whereLambda, Expression> orderLambda1, Expression> orderLambda2, bool isAsc1 = true, bool isAsc2 = true)
319         {
320             if (isAsc1)
321             {
322                 if (isAsc2)
323                 {
324                     return await _db.Set().Where(whereLambda).OrderBy(orderLambda1).ThenBy(orderLambda2).Take(top).AsNoTracking().ToListAsync();
325                 }
326                 else
327                 {
328                     return await _db.Set().Where(whereLambda).OrderBy(orderLambda1).ThenByDescending(orderLambda2).Take(top).AsNoTracking().ToListAsync();
329                 }
330             }
331             else
332             {
333                 if (isAsc2)
334                 {
335                     return await _db.Set().Where(whereLambda).OrderByDescending(orderLambda1).ThenBy(orderLambda2).Take(top).AsNoTracking().ToListAsync();
336                 }
337                 else
338                 {
339                     return await _db.Set().Where(whereLambda).OrderByDescending(orderLambda1).ThenByDescending(orderLambda2).Take(top).AsNoTracking().ToListAsync();
340                 }
341             }
342         }
343         #endregion
344 
345         #endregion SELECT
346 
347         #region 分页
348 
349         #region 6.0 分页查询 + List GetPagedList
350         /// 
351         /// 分页查询 + List GetPagedList
352         /// 
353         /// 
354         /// 页码
355         /// 页容量
356         /// 条件 lambda表达式
357         /// 排序 lambda表达式
358         /// 
359         public async Task> GetPagedList(int pageIndex, int pageSize, Expressionbool>> whereLambda, Expression> orderByLambda, bool isAsc = true)
360         {
361             // 分页 一定注意: Skip 之前一定要 OrderBy
362             if (isAsc)
363             {
364                 return await _db.Set().Where(whereLambda).OrderBy(orderByLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking().ToListAsync();
365             }
366             else
367             {
368                 return await _db.Set().Where(whereLambda).OrderByDescending(orderByLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking().ToListAsync();
369             }
370         }
371         #endregion
372 
373         #region 6.1分页查询 带输出 +List GetPagedList
374         /// 
375         /// 分页查询 带输出
376         /// 
377         /// 
378         /// 
379         /// 
380         /// 
381         /// 
382         /// 
383         /// 
384         /// 
385         public async Task> GetPagedList(Expressionbool>> whereLambda, Expression> orderByLambda, bool isAsc = true, int pageIndex = 1, int pageSize = 20)
386         {
387             var rowCount = await _db.Set().Where(whereLambda).CountAsync();
388 
389             int pageCount = (Math.Ceiling(rowCount.ObjToDecimal() / pageSize.ObjToDecimal())).ObjToInt();
390 
391             List list = null;
392 
393             if (isAsc)
394             {
395                 list = await _db.Set().OrderBy(orderByLambda).Where(whereLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking().ToListAsync();
396             }
397             else
398             {
399                 list = await _db.Set().OrderByDescending(orderByLambda).Where(whereLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking().ToListAsync();
400             }
401 
402             return new PageModel() { dataCount = rowCount, pageCount = pageCount, page = pageIndex, PageSize = pageSize, data = list };
403         }
404         #endregion
405 
406         #endregion
407 
408         #region ORTHER
409 
410         /// 
411         /// 执行存储过程或自定义sql语句--返回集合
412         /// 
413         /// 
414         /// 
415         /// 
416         /// 
417         public async Task> Query(string sql, List parms, CommandType cmdType = CommandType.Text)
418         {
419             //存储过程(exec getActionUrlId @name,@ID)
420             if (cmdType == CommandType.StoredProcedure)
421             {
422                 StringBuilder paraNames = new StringBuilder();
423                 foreach (var sqlPara in parms)
424                 {
425                     paraNames.Append($" @{sqlPara},");
426                 }
427                 sql = paraNames.Length > 0 ? $"exec {sql} {paraNames.ToString().Trim(',')}" : $"exec {sql} ";
428             }
429 
430             return await _db.Set().FromSql(sql).ToListAsync();
431 
432         }
433 
434 
435         /// 
436         /// 回滚
437         /// 
438         public void RollBackChanges()
439         {
440             var items = _db.ChangeTracker.Entries().ToList();
441             items.ForEach(o => o.State = EntityState.Unchanged);
442         }
443 
444         /// 
445         /// 自定义语句和存储过程的增删改--返回影响的行数
446         /// 
447         /// 
448         /// 
449         /// 
450         /// 
451         public async Task<int> Execute(string sql, List parms, CommandType cmdType = CommandType.Text)
452         {
453             //存储过程(exec getActionUrlId @name,@ID)
454             if (cmdType == CommandType.StoredProcedure)
455             {
456                 StringBuilder paraNames = new StringBuilder();
457                 foreach (var sqlPara in parms)
458                 {
459                     paraNames.Append($" @{sqlPara},");
460                 }
461                 sql = paraNames.Length > 0 ?
462                     $"exec {sql} {paraNames.ToString().Trim(',')}" :
463                     $"exec {sql} ";
464             }
465 
466             int ret = await _db.Database.ExecuteSqlCommandAsync(sql, parms.ToArray());
467             return 0;
468         }
469 
470 
471         #endregion ORTHER
472     }
473 }
View Code

BaseRepository中主要是实现了一些基础的CURD操作,并且封装了一些常用的数据库操作。比如分页、执行sql语句等等

如果直接复制以上代码,会报错,因为你的项目中还没有数据上下文:

.netCore+Vue 搭建的简捷开发框架 (2)--仓储层实现和EFCore 的使用_第4张图片

 下面就引入我们将要使用的ORM框架--EFCore

首先,在model层总引入:

Install-Package Microsoft.EntityFrameworkCore -version 2.2.4

Install-Package Microsoft.EntityFrameworkCore.SqlServer -version 2.2.4

Install-Package Microsoft.EntityFrameworkCore.Tools -version 2.2.4

 .netCore+Vue 搭建的简捷开发框架 (2)--仓储层实现和EFCore 的使用_第5张图片

 此系类中我们采用databaseFrist的方式来生成Model文件和上下文。在数据库中先建用于测试的表--Advertisement

语句如下:

 1 USE [BaseCore]
 2 GO
 3 
 4 /****** Object:  Table [dbo].[Advertisement]    Script Date: 08/28/2019 10:43:34 ******/
 5 SET ANSI_NULLS ON
 6 GO
 7 
 8 SET QUOTED_IDENTIFIER ON
 9 GO
10 
11 CREATE TABLE [dbo].[Advertisement](
12     [Id] [int] IDENTITY(1,1) NOT NULL,
13     [Createdate] [datetime] NOT NULL,
14     [ImgUrl] [nvarchar](512) NULL,
15     [Title] [nvarchar](64) NULL,
16     [Url] [nvarchar](256) NULL,
17     [Remark] [nvarchar](max) NULL,
18  CONSTRAINT [PK_dbo.Advertisement] PRIMARY KEY CLUSTERED 
19 (
20     [Id] ASC
21 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
22 ) ON [PRIMARY]
23 
24 GO
View Code

 

然后使用工具Scaffold-DbContext(数据库上下文脚手架)来生成model类文件和DbContext。

命令如下:

Scaffold-DbContext "server=.;database=XXX;uid=sa;pwd=密码;" Microsoft.EntityFrameworkCore.SqlServer -O Models -F  -Context BaseCoreContext 

在执行这个命令之前,需要将Model层设置为启动项目。否则会报错。

 

另外当你的项目Buid没有通过的话,会出现如下错误。

我一般的解决方案就是将其他项目全部先卸载,只留下一个Model,然后再执行以上语句。

这时,在你的Model项目下的Models文件夹下,就会出现如下文件:

打开BaseCoreContext.cs 文件,删除OnConfiguring 方法,至于为什么,我会在后面说明。

为了让数据库上下文也能用DI的方式进行使用,我新建了一个, IBaseContext接口,并且让BaseCoreContext 实现这个接口。

BaseCoreContext.cs

这个时候,仓储的基础父类应该是不会报错。但是我在BaseCoreContext里实现了一个分页操作,用到了一个PageModel 。需要添加到你的Model层里面

代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 
 5 namespace Sincere.Core.Model
 6 {
 7     /// 
 8     /// 通用分页信息类
 9     /// 
10     public class PageModel
11     {
12         /// 
13         /// 当前页标
14         /// 
15         public int page { get; set; } = 1;
16         /// 
17         /// 总页数
18         /// 
19         public int pageCount { get; set; } = 6;
20         /// 
21         /// 数据总数
22         /// 
23         public int dataCount { get; set; } = 0;
24         /// 
25         /// 每页大小
26         /// 
27         public int PageSize { set; get; }
28         /// 
29         /// 返回数据
30         /// 
31         public List data { get; set; }
32 
33     }
34 }
View Code

另外里面还有一些 转换函数,请参考源码:https://github.com/xzhencheng/Sincere.Core.git

至此,项目的仓储层的基础代码就构建完了,今天的作业就先写到这! 

 

你可能感兴趣的:(.netCore+Vue 搭建的简捷开发框架 (2)--仓储层实现和EFCore 的使用)