ef core 批量update 非id_第十节:基于MVC5+Unity+EF+Log4Net的基础结构搭建

一. 前言

本节继续探讨一种新的框架搭建模式,框架的结构划分和上一节是相同的,本节IOC框架换成了Unity,并且采用构造函数注入的方式,另外服务层的封装模式也发生了变化,下面将详细的进行探讨。

(一). 技术选型

1. DotNet框架:4.6

2. 数据库访问:EF 6.2 (CodeFrist模式)

3. IOC框架:Unity 5.8.13

4. 日志框架:log4net 2.0.8

5. 开发工具:VS2017

(二). 框架目标

1. 一个项目同时连接多个相同种类的数据库,在一个方法中可以同时对多个数据进行操作。

2. 支持多种数据库:SqlServer、MySQL、Oracle,灵活的切换数据库。

3. 抽象成支持多种数据库连接方式:EF、ADO.Net、Dapper。

二. 搭建思路

1. 层次划分

将框架分为:Ypf.Data、Ypf.IService、Ypf.Service、Ypf.DTO、Ypf.Utils、Ypf.AdminWeb 六个基本层(后续还会补充 Ypf.Api层),每层的作用分别为:

①. Ypf.Data:存放连接数据库的相关类,包括EF上下文类、映射的实体类、实体类的FluentApi模式的配置类。

②. Ypf.IService:业务接口层,用来约束接口规范。

③. Ypf.Service:业务层,用来编写整套项目的业务方法,但需要符合Ypf.IService层的接口约束。

④. Ypf.DTO: 存放项目中用到的自定义的实体类。

⑤. Ypf.Utils: 工具类

⑥. Ypf.AdminWeb: 表现层,系统的展示、接受用户的交互,传递数据,业务对接。

PS:后续会补充Ypf.Api层,用于接受移动端、或其他客户端接口数据,进行相应的业务对接处理。

2. Ypf.Data层的剖析

把EF封装到【Ypf.Data】层,通过Nuget引入EF的程序集,利用【来自数据库的code first】的模式先进行映射,后续通过DataAnnotations 和 FluentAPI混合使用。该层结构如下:

97ff17612388a7e976074cf7e7df7770.png

PS:EF的关闭默认策略、EF的DataAnnotations、EF的FluentAPI模式, 在关闭数据库策略的情况下,无论哪种模式都需要显式的 ToTable来映射表名,否则会提示该类找不到。

EF配置详情参考:

第十五节: EF的CodeFirst模式通过DataAnnotations修改默认协定

第十六节: EF的CodeFirst模式通过Fluent API修改默认协定

给【Ypf.AdminWeb】层,通过Nuget引入EF的程序集,并配置数据库连接字符串,直接在该层测试数据库访问。【测试通过】

3. Service层和IService层简单的封装一下

①.【Ypf.Service】层只有一个BaseService普通类(非泛型)封装,【Ypf.IService】层有设置一个IBaseService接口,BaseService类实现IBaseService接口,里面的方法全部封装为泛型方法

②.【Ypf.Service】层中有很多自定义的 xxxService,每个xxxService都要实现【Ypf.IService】层的IxxxService层接口,同时继承BaseService类,这里的xxxService层划分并不依赖表名划分,自定义根据业务合理起名即可。

③. xxxService类中,在构造函数中传入DbContext db,但此处并不实例化,而是利用Unity进行构造函数的注入,所有的子类xxxService类中,都注入相应的EF上下文,这样就不需要手动再传入了(这里需要特别注意:Unity默认支持构造函数注入,只要xxxService被配置,那么该类中的(参数最多)的构造函数中的参数类即可以进行注入,只要在配置文件中配置上即可实现注入)。

④.在Unity的配置文件中进行配置IOC,在控制器中进行构造函数注入。

⑤ . 控制器中的Action仅仅负责传值和简单的一些判断,核心业务全部都写在Service层中。

⑥. 子类xxxService中的方法中,可以直接通过 this.XXX的方式调用父类BaseService中的泛型方法,db是通过子类构造函数传到父类BaseService构造函数中。

分享BaseService类和IBaseService接口:

 1 using System; 2 using System.Collections.Generic; 3 using System.Data.Entity; 4 using System.Data.SqlClient; 5 using System.Linq; 6 using System.Linq.Expressions; 7 using System.Reflection; 8 using System.Text; 9 using System.Threading.Tasks; 10 using Ypf.IService; 11  12 namespace Ypf.Service 13 { 14 public class BaseService: IBaseService 15 { 16 ///  17 /// 一个属性,在该类中使用 18 ///  19 public DbContext db { get; private set; } 20  21 ///  22 /// 通过构造函数传入EF的上下文 23 /// 该上下文可能是同种类型的不同数据库、也可能是相同结构的不同类型的数据库 24 /// 为后面的Untiy的构造函数注入埋下伏笔 25 ///  26 ///  27 public BaseService(DbContext db) 28 { 29 this.db = db; 30 } 31  32  33 //1. 直接提交数据库 34  35 #region 01-数据源 36 public IQueryable Entities() where T : class 37 { 38 return db.Set(); 39 } 40  41 #endregion 42  43 #region 02-新增 44 public int Add(T model) where T : class 45 { 46 DbSet dst = db.Set(); 47 dst.Add(model); 48 return db.SaveChanges(); 49  50 } 51 #endregion 52  53 #region 03-删除(适用于先查询后删除 单个) 54 ///  55 /// 删除(适用于先查询后删除的单个实体) 56 ///  57 /// 需要删除的实体 58 ///  59 public int Del(T model) where T : class 60 { 61 db.Set().Attach(model); 62 db.Set().Remove(model); 63 return db.SaveChanges(); 64 } 65 #endregion 66  67 #region 04-根据条件删除(支持批量删除) 68 ///  69 /// 根据条件删除(支持批量删除) 70 ///  71 /// 传入Lambda表达式(生成表达式目录树) 72 ///  73 public int DelBy(Expression> delWhere) where T : class 74 { 75 List listDels = db.Set().Where(delWhere).ToList(); 76 listDels.ForEach(d => 77 { 78 db.Set().Attach(d); 79 db.Set().Remove(d); 80 }); 81 return db.SaveChanges(); 82 } 83 #endregion 84  85 #region 05-单实体修改 86 ///  87 /// 修改 88 ///  89 /// 修改后的实体 90 ///  91 public int Modify(T model) where T : class 92 { 93 db.Entry(model).State = EntityState.Modified; 94 return db.SaveChanges(); 95 } 96 #endregion 97  98 #region 06-批量修改(非lambda) 99 /// 100 /// 批量修改(非lambda)101 /// 102 /// 要修改实体中 修改后的属性 103 /// 查询实体的条件104 /// lambda的形式表示要修改的实体属性名105 /// 106 public int ModifyBy(T model, Expression> whereLambda, params string[] proNames) where T : class107 {108 List listModifes = db.Set().Where(whereLambda).ToList();109 Type t = typeof(T);110 List proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();111 Dictionary dicPros = new Dictionary();112 proInfos.ForEach(p =>113 {114 if (proNames.Contains(p.Name))115 {116 dicPros.Add(p.Name, p);117 }118 });119 foreach (string proName in proNames)120 {121 if (dicPros.ContainsKey(proName))122 {123 PropertyInfo proInfo = dicPros[proName];124 object newValue = proInfo.GetValue(model, null);125 foreach (T m in listModifes)126 {127 proInfo.SetValue(m, newValue, null);128 }129 }130 }131 return db.SaveChanges();132 }133 #endregion134 135 #region 07-根据条件查询136 /// 137 /// 根据条件查询138 /// 139 /// 查询条件(lambda表达式的形式生成表达式目录树)140 /// 141 public List GetListBy(Expression> whereLambda) where T : class142 {143 return db.Set().Where(whereLambda).ToList();144 }145 #endregion146 147 #region 08-根据条件排序和查询148 /// 149 /// 根据条件排序和查询150 /// 151 /// 排序字段类型152 /// 查询条件153 /// 排序条件154 /// 升序or降序155 /// 156 public List GetListBy(Expression> whereLambda, Expression> orderLambda, bool isAsc = true) where T : class157 {158 List list = null;159 if (isAsc)160 {161 list = db.Set().Where(whereLambda).OrderBy(orderLambda).ToList();162 }163 else164 {165 list = db.Set().Where(whereLambda).OrderByDescending(orderLambda).ToList();166 }167 return list;168 }169 #endregion170 171 #region 09-分页查询172 /// 173 /// 根据条件排序和查询174 /// 175 /// 排序字段类型176 /// 页码177 /// 页容量178 /// 查询条件179 /// 排序条件180 /// 升序or降序181 /// 182 public List GetPageList(int pageIndex, int pageSize, Expression> whereLambda, Expression> orderLambda, bool isAsc = true) where T : class183 {184 185 List list = null;186 if (isAsc)187 {188 list = db.Set().Where(whereLambda).OrderBy(orderLambda)189 .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();190 }191 else192 {193 list = db.Set().Where(whereLambda).OrderByDescending(orderLambda)194 .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();195 }196 return list;197 }198 #endregion199 200 #region 10-分页查询输出总行数201 /// 202 /// 根据条件排序和查询203 /// 204 /// 排序字段类型205 /// 页码206 /// 页容量207 /// 查询条件208 /// 排序条件209 /// 升序or降序210 /// 211 public List GetPageList(int pageIndex, int pageSize, ref int rowCount, Expression> whereLambda, Expression> orderLambda, bool isAsc = true) where T : class212 {213 int count = 0;214 List list = null;215 count = db.Set().Where(whereLambda).Count();216 if (isAsc)217 {218 var iQueryList = db.Set().Where(whereLambda).OrderBy(orderLambda)219 .Skip((pageIndex - 1) * pageSize).Take(pageSize);220 221 list = iQueryList.ToList();222 }223 else224 {225 var iQueryList = db.Set().Where(whereLambda).OrderByDescending(orderLambda)226 .Skip((pageIndex - 1) * pageSize).Take(pageSize);227 list = iQueryList.ToList();228 }229 rowCount = count;230 return list;231 }232 #endregion233 234 235 //2. SaveChange剥离出来,处理事务236 237 #region 01-批量处理SaveChange()238 /// 239 /// 事务批量处理240 /// 241 /// 242 public int SaveChange()243 {244 return db.SaveChanges();245 }246 #endregion247 248 #region 02-新增249 /// 250 /// 新增251 /// 252 /// 需要新增的实体253 public void AddNo(T model) where T : class254 {255 db.Set().Add(model);256 }257 #endregion258 259 #region 03-删除260 /// 261 /// 删除262 /// 263 /// 需要删除的实体264 public void DelNo(T model) where T : class265 {266 db.Entry(model).State = EntityState.Deleted;267 }268 #endregion269 270 #region 04-根据条件删除271 /// 272 /// 条件删除273 /// 274 /// 需要删除的条件275 public void DelByNo(Expression> delWhere) where T : class276 {277 List listDels = db.Set().Where(delWhere).ToList();278 listDels.ForEach(d =>279 {280 db.Set().Attach(d);281 db.Set().Remove(d);282 });283 }284 #endregion285 286 #region 05-修改287 /// 288 /// 修改289 /// 290 /// 修改后的实体291 public void ModifyNo(T model) where T : class292 {293 db.Entry(model).State = EntityState.Modified;294 }295 #endregion296 297 298 //3. EF调用sql语句299 300 #region 01-执行增加,删除,修改操作(或调用存储过程)301 /// 302 /// 执行增加,删除,修改操作(或调用存储过程)303 /// 304 /// 305 /// 306 /// 307 public int ExecuteSql(string sql, params SqlParameter[] pars)308 {309 return db.Database.ExecuteSqlCommand(sql, pars);310 }311 312 #endregion313 314 #region 02-执行查询操作315 /// 316 /// 执行查询操作317 /// 318 /// 319 /// 320 /// 321 /// 322 public List ExecuteQuery(string sql, params SqlParameter[] pars) where T : class323 {324 return db.Database.SqlQuery(sql, pars).ToList();325 }326 #endregion327 328 329 330 }331 }
 1 using System; 2 using System.Collections.Generic; 3 using System.Data.SqlClient; 4 using System.Linq; 5 using System.Linq.Expressions; 6 using System.Text; 7 using System.Threading.Tasks; 8  9 namespace Ypf.IService 10 { 11 public interface IBaseService 12 { 13 //1. 直接提交数据库 14  15 #region 01-数据源 16 IQueryable Entities() where T : class; 17  18 #endregion 19  20 #region 02-新增 21 int Add(T model) where T : class; 22  23 #endregion 24  25 #region 03-删除(适用于先查询后删除 单个) 26 ///  27 /// 删除(适用于先查询后删除的单个实体) 28 ///  29 /// 需要删除的实体 30 ///  31 int Del(T model) where T : class; 32  33 #endregion 34  35 #region 04-根据条件删除(支持批量删除) 36 ///  37 /// 根据条件删除(支持批量删除) 38 ///  39 /// 传入Lambda表达式(生成表达式目录树) 40 ///  41 int DelBy(Expression> delWhere) where T : class; 42  43 #endregion 44  45 #region 05-单实体修改 46 ///  47 /// 修改 48 ///  49 /// 修改后的实体 50 ///  51 int Modify(T model) where T : class; 52  53 #endregion 54  55 #region 06-批量修改(非lambda) 56 ///  57 /// 批量修改(非lambda) 58 ///  59 /// 要修改实体中 修改后的属性  60 /// 查询实体的条件 61 /// lambda的形式表示要修改的实体属性名 62 ///  63 int ModifyBy(T model, Expression> whereLambda, params string[] proNames) where T : class; 64  65 #endregion 66  67 #region 07-根据条件查询 68 ///  69 /// 根据条件查询 70 ///  71 /// 查询条件(lambda表达式的形式生成表达式目录树) 72 ///  73 List GetListBy(Expression> whereLambda) where T : class; 74  75 #endregion 76  77 #region 08-根据条件排序和查询 78 ///  79 /// 根据条件排序和查询 80 ///  81 /// 排序字段类型 82 /// 查询条件 83 /// 排序条件 84 /// 升序or降序 85 ///  86 List GetListBy(Expression> whereLambda, Expression> orderLambda, bool isAsc = true) where T : class; 87  88 #endregion 89  90 #region 09-分页查询 91 ///  92 /// 根据条件排序和查询 93 ///  94 /// 排序字段类型 95 /// 页码 96 /// 页容量 97 /// 查询条件 98 /// 排序条件 99 /// 升序or降序100 /// 101 List GetPageList(int pageIndex, int pageSize, Expression> whereLambda, Expression> orderLambda, bool isAsc = true) where T : class;102 103 #endregion104 105 #region 10-分页查询输出总行数106 /// 107 /// 根据条件排序和查询108 /// 109 /// 排序字段类型110 /// 页码111 /// 页容量112 /// 查询条件113 /// 排序条件114 /// 升序or降序115 /// 116 List GetPageList(int pageIndex, int pageSize, ref int rowCount, Expression> whereLambda, Expression> orderLambda, bool isAsc = true) where T : class;117 118 #endregion119 120 121 //2. SaveChange剥离出来,处理事务122 123 #region 01-批量处理SaveChange()124 /// 125 /// 事务批量处理126 /// 127 /// 128 int SaveChange();129 130 #endregion131 132 #region 02-新增133 /// 134 /// 新增135 /// 136 /// 需要新增的实体137 void AddNo(T model) where T : class;138 139 #endregion140 141 #region 03-删除142 /// 143 /// 删除144 /// 145 /// 需要删除的实体146 void DelNo(T model) where T : class;147 148 #endregion149 150 #region 04-根据条件删除151 /// 152 /// 条件删除153 /// 154 /// 需要删除的条件155 void DelByNo(Expression> delWhere) where T : class;156 157 #endregion158 159 #region 05-修改160 /// 161 /// 修改162 /// 163 /// 修改后的实体164 void ModifyNo(T model) where T : class;165 166 #endregion167 168 169 //3. EF调用sql语句170 171 #region 01-执行增加,删除,修改操作(或调用存储过程)172 /// 173 /// 执行增加,删除,修改操作(或调用存储过程)174 /// 175 /// 176 /// 177 /// 178 int ExecuteSql(string sql, params SqlParameter[] pars);179 180 #endregion181 182 #region 02-执行查询操作183 /// 184 /// 执行查询操作185 /// 186 /// 187 /// 188 /// 189 /// 190 List ExecuteQuery(string sql, params SqlParameter[] pars) where T : class;191 192 #endregion193 194 }195 }

4. 利用Unity进行整合

(1). 通过Nuget给【Ypf.Utils】层引入“Unity”的程序集和“Microsoft.AspNet.Mvc”程序集。

(2). 新建类:DIFactory 用于读取Unity配置文件创建Unity容器。需要引入程序集“System.Configuration”

新建类:UnityControllerFactory 用于自定义控制器实例化工厂。需要引入程序集“System.Web”。

分享代码:

 1 using Microsoft.Practices.Unity; 2 using Microsoft.Practices.Unity.Configuration; 3 using System; 4 using System.Collections.Generic; 5 using System.Configuration; 6 using System.IO; 7 using System.Linq; 8 using System.Text; 9 using System.Threading.Tasks;10 using Unity;11 12 namespace Ypf.Utils13 {14 /// 15 /// 依赖注入工厂(单例的 采用双if+lock锁)16 /// 读取Unity的配置文件,并创建Unity容器17 /// 18 public class DIFactory19 {20 //静态的私有变量充当Lock锁21 private static object _lock = new object();22 private static Dictionary _UnityDictory = new Dictionary();23 24 /// 25 /// 获取Unity容器26 /// 27 /// 对应配置文件中节点的名称,同时也当做字典中的key值28 /// 29 public static IUnityContainer GetContainer(string containerName = "EFContainer")30 {31 if (!_UnityDictory.ContainsKey(containerName))32 {33 lock (_lock)34 {35 if (!_UnityDictory.ContainsKey(containerName))36 {37 //1. 固定的4行代码读取配置文件38 ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();39 fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles甥楮祴Config.xml");//找配置文件的路径40 Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);41 UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);42 //2. Unity层次的步骤43 IUnityContainer container = new UnityContainer();44 section.Configure(container, containerName);45 //3.将创建好的容器放到字典里46 _UnityDictory.Add(containerName, container);47 }48 } 49 }50 return _UnityDictory[containerName];51 }52 }53 }
 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Web.Mvc; 7 using System.Web.Routing; 8 using Unity; 9 10 namespace Ypf.Utils11 {12 /// 13 /// 自定义控制器实例化工厂14 /// 15 public class UnityControllerFactory : DefaultControllerFactory16 {17 private IUnityContainer UnityContainer18 {19 get20 {21 return DIFactory.GetContainer();22 }23 }24 25 /// 26 /// 创建控制器对象27 /// 28 /// 29 /// 30 /// 31 protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)32 {33 if (null == controllerType)34 {35 return null;36 }37 IController controller = (IController)this.UnityContainer.Resolve(controllerType);38 return controller;39 }40 41 /// 42 /// 释放控制器43 /// 44 /// 45 public override void ReleaseController(IController controller)46 {47 //this.UnityContainer.Teardown(controller);//释放对象(老版本)48 49 base.ReleaseController(controller);50 }51 }52 }

(3). 通过Nuget给【Ypf.AdminWeb】层引入“Unity”的程序集,并新建CfgFiles文件夹和UnityConfig.xml文件,该xml文件需要改属性为“始终复制”。

分享代码:

 1  2  3  4  5  6  7   8  9 10 11 12 15 16 17 18 19 20 21 22 23 24 25 26 27 

(4). 将【Ypf.Service】层的程序集生成路径改为:..Ypf.AdminWebbin

(5). 在【Ypf.AdminWeb】层中的Global文件中进行注册 ,用Unity代替原有的控制器创建流程.

 //注册自定义实例化控制器的容器(利用Unity代替原有的控制器创建流程)

ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());

 PS:横向对比,AutoFac中也有一句类似的话:

a2c2135e6044f5149354e8ba89d0db82.png

在【Ypf.AdminWeb】层测试Untiy的IOC和DI【测试通过】

5. 将Log4net整合到Ypf.Utils层中。

(1). 通过Nuget给【Ypf.Utils】层添加“Log4net”程序集。

(2). 新建Log文件,拷贝“log4net.xml”和“LogUtils.cs”两个类文件,“log4net.xml”要改为嵌入的资源。

(3). 在【Ypf.Admin】层的Global文件中进行注册。LogUtils.InitLog4Net();

(4). 解析:主要配置了两种模式,输出到“txt文本文档”和“SQLServer数据库中”。其中“文本文档”又分了两种模式,全部输入到一个文档中 和 不同类型的日志输入到不同文档下,在调用的时候通过传入参数来区分存放在哪个文件夹下。

代码详见下面的实战测试。

6. 完善【Ypf.Service】层中BaseService的封装,封装EF常用的增删改查的方法,这里暂时先不扩展EF插件的方法。

代码见上

7. 如何控制EF上下文中的生命周期呢?

在配置文件中可以通过lifetime这个节点进行配置,而上一套框架的模式是直接通过using的模式进行配置,这里可以使用默认的方式:每次使用时候都创建。

详见Unity专题:

Unity深入浅出(一)

Unity深入浅出(二)

三. 剖析核心

1. 相同数据库结构,不同类型的数据库如何快速切换。

解析:首先需要明白的是不同的数据库切换,实质上切换的就是 EF的上下文,该框架的模式EF的是使用Unity通过xxxService中子类的构造函数注入,需要在配置文件中配置构造函数注入EF上下文。

 所以这里切换数据库(eg:SQLServer→MySQL)只需要通过Nuget引出EF对应数据库的程序集,编写好配置文件,将SQLServer的EF上下文(MyDbContext1)切换成MySQL的上下文即可。

【需要测试】

2. 在一个方法中如何同时访问多个数据库,并对其进行事务一体的增删改操作。

 解析:首先需要在BaseService的构造函数参数拼写多个DbContext参数,

91889786b758c9e451aeb17f55c0cee9.png

 其次子类xxxService中同样也需要多个DbContext参数,当多个参数时候,需要通过命名的方式指定注入,否则相互覆盖,不能分别注入。

7c878cc6fd28cf31c9cc76e0c685717c.png

最后,Unity的配置文件也需要通过命名的方式进行注入。

3f83644775b2d609de8a1ab8b5027964.png

思考,Dependency特性写在父类BaseService中是否可以?

答案:经测试,不可以,EF的命名方式的构造函数注入要写在子类xxxService中。

同时会带来一个弊端?

由于BaseSevice类中泛型方法中的db,直接使用默认一个数据库的时候的db属性,所有导致当一个方法中如果涉及到多个上下文,没法直接使用BaseService中的封装方法,需要写原生代码,有点麻烦。

如下图:

86b16df672e329589395a0a5410316ea.png

那么如何解决这个问题?

3. 连接多个数据库框架的局限性,如何改进。

将BaseSevice中的泛型方法使用的db通过参数的形式进行传入,而且默认为一个数据库时候对应的DbContext属性,这样当只有一个数据库的时候,不用管它,因为他有默认值;当需要同时操控数据库的时候,在子类XXXService中,根据需要传入相应的db接口。

【经测试,不可以,提示 默认参数必须是编译时候的常量】

后续将采用别的方案进行处理,请期待。

四. 实战测试

这里准备两个数据库,分别是:YpfFrame_DB 和 YpfFrameTest_DB

①:YpfFrame_DB中,用到了表:T_SysUser 和 T_SysLoginLog,表结构如下

0ab6043b4dcdb0fa8596aa3252306761.png
9386cf7956e50e002fd86ca1c417c355.png

②. YpfFrameTest_DB 表中用到了T_SchoolInfor,表结构如下

72eabf91a28987772e936c8be8682d31.png

开始测试

1. 测试增删改查,包括基本的事务一体。

在【Ypf.IService】层中新建ITestService接口,在【Ypf.Service】层中新建TestService类,实现ITestService接口, 定义TestBasicCRUD方法,进行测试,代码如下。

 1 ///  2 /// 1.测试基本的增删改查,事务一体 3 ///  4 ///  5 public int TestBasicCRUD() 6 { 7 //1.增加操作 8 T_SysUser t_SysUser = new T_SysUser() 9 {10 id = Guid.NewGuid().ToString("N"),11 userAccount = "123456
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值