EF通用数据层封装类(支持读写分离,一主多从)

浅谈orm

  记得四年前在学校第一次接触到 Ling to Sql,那时候瞬间发现不用手写sql语句是多么的方便,后面慢慢的接触了许多orm框架,像 EF,Dapper,Hibernate,ServiceStack.OrmLite 等。当然每种orm都有各自的优势,也有不足的地方。园子里也有很多大神开源了他们写的orm,如SqlSugar,Chloe.ORM,CYQ.Data 等。先不说这些开源的orm使用度怎么样,我觉得起码从开源的精神上就很可嘉了,我也曾下载过这几位大神的源码进行学习。
  所有orm最终体现的一点就是方便,减少程序员重复性的工作,当然目前还有一些公司还是使用手写sql的方式来做,我觉得整个项目都使用手写sql来做真的是有点闲到蛋疼,并不是不推荐手写sql的方式,只是个人觉得最基本的增删改查这些都手写的话,那其实考验不是能力,而是耐力。有人说手写sql的方式可控性强,性能高,我想说的是orm也能做到,关键是你怎么去使用。
  orm的优点非常明显,开发便捷,但或许也是由于这个优点,让很多偷懒的程序员也会渐渐忘了sql语句的写法,我遇到过很多的程序员朋友用了EF后,手写sql,视图、存储过程这些都不想用了,我个人觉手写sql这种还是必要的。不然某一天你看到别人的程序里面写着 “exec  xxxx”,你就会突然觉得“啊,好像在哪里见过.....”。所以我想说的是“该出手时还是得出手"。


浅谈Entity Framework

  Entity Framework 是微软家的orm框架,随着 Entity Framework 不断的完善强化,目前相信使用的比例相对其他的orm来说还是较高的。像我目前使用的最多的就是EF和Dapper。确实,EF用起来开发过程中会方便很多,毕竟EF走过了这么年头,无论是成熟度,还是性能等都提高了很多,也有很多开发者为EF提供了扩展功能,如entity framework extended 等。而且作为.net开发者来说项目通用性也很强,资料也多,微软在这块的更新力度也很给力。不过之前刚出的EF Core也存在一些坑,毕竟还是初期阶段,相信现在后面会越来越好的。

  Entity Framework  提供了三种开发模式,code first,db first,model first。目前用的最多的就属code first了。至于这三种模式的简单使用和区别,大家可以参考下这篇文章。

  我曾听一些朋友说过说EF使用起来性能很差,生成的sql语句很难看等。我觉得说这种话之前还是先检查下代码或者多看下一些EF文章吧,要先确保自己没给自己挖坑,然后才能指责别人的不好。如果真心觉得EF或者其他的orm用起来很不爽,那就自己写一个吧,我也曾经和同事用Dapper扩展一个通用的orm,当时是出于一种学习和使用方便的角度。


Entity Framework 通用数据层类

  这里提供下 EF 通用数据层父类方法,其实网上也有很多人提供了自己项目中的 EF 通用数据层父类方法,所以这里提供的并不是最优和最好的选择,只能说是可以通用的类,方便大家学习和使用,具体代码如下:

DbContextFactory DbContext工厂类

    public class DbContextFactory{        public  DbContext GetDbContext(){            string key = typeof(DBContext.DbContextFactory).Name + "XJHDbContext";DbContext dbContext = CallContext.GetData(key) as DbContext;        
if (dbContext == null){dbContext = new XJHDbContext();CallContext.SetData(key, dbContext);} return dbContext;}}


扩展类,实现读写分离

  上面的通用类是比较基础简单通用的,适合于单库读写操作。对于EF实现读写分离,之前网上找过类似的参考文章,很多人文章都是使用 DbCommandInterceptor拦截器 来实现,具体的做法是通过拦截到sql语句,然后根据具体条件去判断是走主库还是从库。这种做法不是不行,只是个人感觉不是很好扩展,而且要在拦截器里面做限制判断。

  其实说白了EF本身就是一个读写分离的orm。用过EF的人知道,EF提供访问数据库的是 DbContext 这个对象,所以想实现读写分离的就很简单了,只要在程序中使用两个不同的DbContext对象,一个负责读,一个负责写就好了。

  所以在上面提供的通用封装类中稍微做下修改,修改如下DbContextFactory中获取DbContext的方法,实现一个读的DbContext和一个写的DbContext对象的获取。

  这里要注意下,对于读的DbContext来说,要做下设置
  1.使用 Database.SetInitializer(new NullDatabaseInitializer<ReadDbContext>()); 改变ef初始化策略,因为一般我们使用读写分离的话从库都是同步于主库的,所以不使用ef的自动创建数据库策略。
  2.重写 SaveChanges 方法,对应从库来说,只提供读取的功能,所以防止误操作,这里禁用掉SaveChanges方法,一般需要使用从读的保存方法,就对外抛出异常。

  代码如下:

支持读写分离的 DbContextFactory 类

  public class DbContextFactory{        public DbContext GetWriteDbContext(){            string key = typeof(DbContextFactory).Name + "WriteDbContext";DbContext dbContext = CallContext.GetData(key) as DbContext;         
if (dbContext == null){dbContext = new WriteDbContext();CallContext.SetData(key, dbContext);} return dbContext;} public DbContext GetReadDbContext(){ string key = typeof(DbContextFactory).Name + "ReadDbContext";DbContext dbContext = CallContext.GetData(key) as DbContext;
if (dbContext == null){dbContext = new ReadDbContext();CallContext.SetData(key, dbContext);} return dbContext;}}

   对应的 DbBase 类也做下修改,主要将上面的Db对象改作 MasterDb  SlaveDb 对象,并且把上面的读写方法坐下调整,修改后如下:

支持读写分离的 DbBase类

public class DbBase{        //是否读写分离(可以配置在配置文件中)private static readonly bool IsReadWriteSeparation = true;    
#region EF上下文对象(主库) protected DbContext MasterDb => _masterDb.Value;

private readonly Lazy<DbContext> _masterDb = new Lazy<DbContext>(() =>
new DbContextFactory().GetWriteDbContext());
#endregion EF上下文对象(主库)
#region EF上下文对象(从库)
protected DbContext SlaveDb => IsReadWriteSeparation ? _slaveDb.Value : _masterDb.Value; private readonly Lazy<DbContext> _slaveDb = new Lazy<DbContext>(() => new DbContextFactory().GetReadDbContext()); #endregion EF上下文对象(从库) #region 自定义其他方法 /// <summary>/// 执行存储过程或自定义sql语句--返回集合(自定义返回类型)        /// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdType"></param>/// <returns></returns>public List<TModel> Query<TModel>(string sql, List<SqlParameter> parms, CommandType cmdType = CommandType.Text){ //存储过程(exec getActionUrlId @name,@ID)if (cmdType == CommandType.StoredProcedure){StringBuilder paraNames = new StringBuilder();
foreach (var sqlPara in parms){paraNames.Append($" @{sqlPara},");}sql = paraNames.Length > 0 ? $"exec {sql} {paraNames.ToString().Trim(',')}" : $"exec {sql} ";} var list = SlaveDb.Database.SqlQuery<TModel>(sql, parms.ToArray()); var enityList = list.ToList(); return enityList;} /// <summary>/// 自定义语句和存储过程的增删改--返回影响的行数        /// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdType"></param>/// <returns></returns>public int Execute(string sql, List<SqlParameter> parms, CommandType cmdType = CommandType.Text){ //存储过程(exec getActionUrlId @name,@ID)if (cmdType == CommandType.StoredProcedure){StringBuilder paraNames = new StringBuilder(); foreach (var sqlPara in parms){paraNames.Append($" @{sqlPara},");}sql = paraNames.Length > 0 ?$"exec {sql} {paraNames.ToString().Trim(',')}" :$"exec {sql} ";} int ret = MasterDb.Database.ExecuteSqlCommand(sql, parms.ToArray()); return ret;} #endregion 自定义其他方法} /// <summary>/// mssql数据库 数据层 父类    /// </summary>/// <typeparam name="T"></typeparam>public class DbBase<T> : DbBase where T : class, new(){ #region INSERT /// <summary>/// 新增 实体        /// </summary>/// <param name="model"></param>/// <returns></returns>public void Insert(T model){MasterDb.Set<T>().Add(model);} /// <summary>/// 普通批量插入        /// </summary>/// <param name="datas"></param>public void InsertRange(List<T> datas){MasterDb.Set<T>().AddRange(datas);} #endregion INSERT #region DELETE /// <summary>/// 根据模型删除        /// </summary>/// <param name="model">包含要删除id的对象</param>/// <returns></returns>public void Delete(T model){MasterDb.Set<T>().Attach(model);MasterDb.Set<T>().Remove(model);} /// <summary>/// 删除        /// </summary>/// <param name="whereLambda"></param>public void Delete(Expression<Func<T, bool>> whereLambda){MasterDb.Set<T>().Where(whereLambda).Delete();} #endregion DELETE #region UPDATE /// <summary>/// 单个对象指定列修改        /// </summary>/// <param name="model">要修改的实体对象</param>/// <param name="proNames">要修改的 属性 名称</param>/// <param name="isProUpdate"></param>/// <returns></returns>public void Update(T model, List<string> proNames, bool isProUpdate = true){ //将 对象 添加到 EF中MasterDb.Set<T>().Attach(model); var setEntry = ((IObjectContextAdapter)MasterDb).ObjectContext.ObjectStateManager.GetObjectStateEntry(model); //指定列修改if (isProUpdate){ foreach (string proName in proNames){setEntry.SetModifiedProperty(proName);}} //忽略类修改else{Type t = typeof(T);List<PropertyInfo> proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList(); foreach (var item in proInfos){ string proName = item.Name; if (proNames.Contains(proName)){ continue;}setEntry.SetModifiedProperty(proName);}}} /// <summary>/// 单个对象修改        /// </summary>/// <param name="model"></param>/// <returns></returns>public void Update(T model){DbEntityEntry entry = MasterDb.Entry<T>(model);MasterDb.Set<T>().Attach(model);entry.State = EntityState.Modified;} /// <summary>/// 批量修改        /// </summary>/// <param name="whereLambda"></param>/// <param name="updateExpression"></param>public void Update(Expression<Func<T, bool>> whereLambda, Expression<Func<T, T>> updateExpression){MasterDb.Set<T>().Where(whereLambda).Update(updateExpression);} /// <summary>/// 批量修改        /// </summary>/// <param name="models"></param>/// <returns></returns>public void UpdateAll(List<T> models){ foreach (var model in models){DbEntityEntry entry = MasterDb.Entry(model);entry.State = EntityState.Modified;}} /// <summary>/// 批量统一修改        /// </summary>/// <param name="model">要修改的实体对象</param>/// <param name="whereLambda">查询条件</param>/// <param name="modifiedProNames"></param>/// <returns></returns>public void Update(T model, Expression<Func<T, bool>> whereLambda,
params string[] modifiedProNames){ //查询要修改的数据List<T> listModifing = MasterDb.Set<T>().Where(whereLambda).ToList();Type t = typeof(T);List<PropertyInfo> proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();Dictionary<string, PropertyInfo> dictPros = new Dictionary<string, PropertyInfo>();proInfos.ForEach(p =>{ if (modifiedProNames.Contains(p.Name)){dictPros.Add(p.Name, p);}}); if (dictPros.Count <= 0){ throw new Exception("指定修改的字段名称有误或为空");} foreach (var item in dictPros){PropertyInfo proInfo = item.Value; //取出 要修改的值object newValue = proInfo.GetValue(model, null); //批量设置 要修改 对象的 属性foreach (T oModel in listModifing){ //为 要修改的对象 的 要修改的属性 设置新的值proInfo.SetValue(oModel, newValue, null);}}} #endregion UPDATE #region SELECT /// <summary>/// 根据主键查询        /// </summary>/// <param name="id"></param>/// <returns></returns>public T FindById(dynamic id){ return SlaveDb.Set<T>().Find(id);} /// <summary>/// 获取默认一条数据,没有则为NULL        /// </summary>/// <param name="whereLambda"></param>/// <returns></returns>public T FirstOrDefault(Expression<Func<T, bool>> whereLambda = null){ if (whereLambda == null){ return SlaveDb.Set<T>().FirstOrDefault();} return SlaveDb.Set<T>().FirstOrDefault(whereLambda);} /// <summary>/// 获取全部数据        /// </summary>/// <returns></returns>public List<T> GetAll(string ordering = null){ return ordering == null? SlaveDb.Set<T>().ToList(): SlaveDb.Set<T>().OrderBy(ordering).ToList();} /// <summary>/// 带条件查询获取数据        /// </summary>/// <param name="whereLambda"></param>/// <param name="ordering"></param>/// <returns></returns>public List<T> GetAll(Expression<Func<T, bool>> whereLambda, string ordering = null){ var iQueryable = SlaveDb.Set<T>().Where(whereLambda);
return ordering == null? iQueryable.ToList(): iQueryable.OrderBy(ordering).ToList();} /// <summary>/// 带条件查询获取数据        /// </summary>/// <param name="whereLambda"></param>/// <returns></returns>public IQueryable<T> GetAllIQueryable(Expression<Func<T, bool>> whereLambda = null){ return whereLambda == null ? SlaveDb.Set<T>() : SlaveDb.Set<T>().Where(whereLambda);} /// <summary>/// 获取数量        /// </summary>/// <param name="whereLambd"></param>/// <returns></returns>public int GetCount(Expression<Func<T, bool>> whereLambd = null){
return whereLambd == null ? SlaveDb.Set<T>().Count()
: SlaveDb.Set<T>().Where(whereLambd).Count();} /// <summary>/// 判断对象是否存在        /// </summary>/// <param name="whereLambd"></param>/// <returns></returns>public bool Any(Expression<Func<T, bool>> whereLambd){ return SlaveDb.Set<T>().Where(whereLambd).Any();} /// <summary>/// 分页查询        /// </summary>/// <param name="pageIndex">当前页码</param>/// <param name="pageSize">每页大小</param>/// <param name="rows">总条数</param>/// <param name="orderBy">排序条件(一定要有)</param>/// <param name="whereLambda">查询添加(可有,可无)</param>/// <param name="isOrder">是否是Order排序</param>/// <returns></returns>public List<T> Page<TKey>(int pageIndex, int pageSize, out int rows,
Expression<Func<T, TKey>> orderBy, Expression<Func<T, bool>> whereLambda = null,
bool isOrder = true){IQueryable<T> data = isOrder ?SlaveDb.Set<T>().OrderBy(orderBy) :SlaveDb.Set<T>().OrderByDescending(orderBy);
if (whereLambda != null){data = data.Where(whereLambda);}rows = data.Count();
return data.PageBy((pageIndex - 1) * pageSize, pageSize).ToList();} /// <summary>/// 分页查询        /// </summary>/// <param name="pageIndex">当前页码</param>/// <param name="pageSize">每页大小</param>/// <param name="rows">总条数</param>/// <param name="ordering">排序条件(一定要有)</param>/// <param name="whereLambda">查询添加(可有,可无)</param>/// <returns></returns>public List<T> Page(int pageIndex, int pageSize, out int rows,
string ordering, Expression<Func<T, bool>> whereLambda = null){ // 分页 一定注意: Skip 之前一定要 OrderByvar data = SlaveDb.Set<T>().OrderBy(ordering);
if (whereLambda != null){data = data.Where(whereLambda);}rows = data.Count();
return data.PageBy((pageIndex - 1) * pageSize, pageSize).ToList();} /// <summary>/// 查询转换        /// </summary>/// <typeparam name="TDto"></typeparam>/// <param name="whereLambda"></param>/// <returns></returns>public List<TDto> Select<TDto>(Expression<Func<T, bool>> whereLambda){ return SlaveDb.Set<T>().Where(whereLambda).Select<TDto>().ToList();} #endregion SELECT #region ORTHER /// <summary>/// 执行存储过程或自定义sql语句--返回集合        /// </summary>/// <param name="sql"></param>/// <param name="parms"></param>/// <param name="cmdType"></param>/// <returns></returns>public List<T> Query(string sql, List<SqlParameter> parms, CommandType cmdType = CommandType.Text){ return Query<T>(sql, parms, cmdType);} /// <summary>/// 提交保存        /// </summary>/// <returns></returns>public int SaveChanges(){ return MasterDb.SaveChanges();} /// <summary>/// 回滚        /// </summary>public void RollBackChanges(){ var items = MasterDb.ChangeTracker.Entries().ToList();items.ForEach(o => o.State = EntityState.Unchanged);} #endregion ORTHER}

  这样简单的读写分离就实现了,实现逻辑也比较清晰,方便扩展。


进一步改造,实现多从库读取

  一般做读写分离,都会做一主多从,特别对读取量比较大的项目,这样多库读取就能减轻读库的压力。所以对于上面的方法,做下改造。
  上面可以看到,主库和从库都是通过 DbContextFactory 这个类来获取的,在GetReadDbContext 方法中每次都是获取 ReadDbContext 这个对象。那么对于多个从库的情况下,每次读取到底要去哪个库读取数据呢?这里就是一个算法规则的问题了,或者说是策略吧,如果使用过nginx的朋友就知道,nginx本身内部在实现负载均衡的时候提供了多种策略,比如轮询,加权轮询,ip_hash等策略。其实上面获取同一个ReadDbContext 的方法也算一种策略,叫单一策略,每次都获取单一的对象。

  多从库的情况下,我们简单的来实现另一种获取策略,随机策略,每次都随机获取到一个从库的对象,这种是最简单的策略,当然,正式使用的话大家可以发挥自己的创造力,写出多了的算法策略。

首先,定义一个策略接口,方便策略的扩展和切换,代码如下:

IReadDbStrategy 接口

 /// <summary>/// 从数据库获取策略接口  /// </summary>public interface IReadDbStrategy{      /// <summary>/// 获取读库      /// </summary>/// <returns></returns>DbContext GetDbContext();}

单从库情况下,定义一个单一策略,代码如下:

单一策略

   /// <summary>/// 单一策略   /// </summary>public class SingleStrategy : IReadDbStrategy{       public DbContext GetDbContext(){           return new ReadDbContext();}}

多从库情况下,定义一个随机策略,代码如下:

随机策略

    /// <summary>/// 随机策略    /// </summary>public class RandomStrategy : IReadDbStrategy{        //所有读库类型public static List<Type> DbTypes; static RandomStrategy(){LoadDbs();} //加载所有的读库类型static void LoadDbs(){DbTypes = new List<Type>();      
var assembly = Assembly.GetExecutingAssembly();
var types = assembly.GetTypes();
foreach (var type in types){ if (type.BaseType == typeof(BaseReadDbContext)){DbTypes.Add(type);}}} public DbContext GetDbContext(){ int randomIndex = new Random().Next(0, DbTypes.Count);
var dbType = DbTypes[randomIndex];
var dbContext = Activator.CreateInstance(dbType) as DbContext;
return dbContext;}}

  这样,所有从库我们都基于策略去获取,扩展也比较方便。修改下 DbContextFactory 类的 GetReadDbContext 方法,通过策略接口来获取,代码如下:

支持一主多从的 DbContextFactory 类

  public class DbContextFactory{        //todo:这里可以自己通过注入的方式来实现,就会更加灵活private static readonly IReadDbStrategy ReadDbStrategy = new RandomStrategy();        public DbContext GetWriteDbContext(){            string key = typeof(DbContextFactory).Name + "WriteDbContext";DbContext dbContext = CallContext.GetData(key) as DbContext;      

if (dbContext == null){dbContext = new WriteDbContext();CallContext.SetData(key, dbContext);} return dbContext;} public DbContext GetReadDbContext(){ string key = typeof(DbContextFactory).Name + "ReadDbContext";DbContext dbContext = CallContext.GetData(key) as DbContext;
if (dbContext == null){dbContext = ReadDbStrategy.GetDbContext();CallContext.SetData(key, dbContext);} return dbContext;}}


  这样简单的一主多从也实现了。


参考文章

  http://www.cnblogs.com/zhaopei/p/5721789.html
  http://www.cnblogs.com/GuZhenYin/p/5482288.html

回到顶部

源码分享

  所有的代码提供给大家的更多的是一种思路和学习的参考,如果有什么不足的地方也欢迎大家批评指正,如果觉得对你有帮助,不要吝啬你的鼠标,帮忙点个星,点个赞吧。

  源码地址: https://github.com/qq1206676756/EF_DbHelper

原文地址:http://www.cnblogs.com/qtqq/p/6942312.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325316.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端进行时间段筛选

传给后端参数时进行格式化 weekResultTimeStart:params.insertTime!null?moment(params.insertTime[0]).format(YYYY-MM-DD HH:mm:ss):null,weekResultTimeEnd:params.insertTime!null?moment(params.insertTime[1]).format(YYYY-MM-DD HH:mm:ss):null,注意点&#xff1a; 前…

IdentityServer4(OAuth2.0服务)折腾笔记

以下&#xff0c;称这个使用了IdentityServer4的OAuth2.0服务的项目称为Passport项目。 组件说明&#xff08;Nuget&#xff09; Passport项目所需组件 项目以Asp.net Core Identity项目模板初始化&#xff0c;集成IdentityServer4中间件&#xff1b;集成IdentityServer4.AspN…

map遍历进行展示

{userList.map((item,index)> <Option key{index} value{item.userId}>{item.realName||null}</Option>)||null}

Javase基础

Javase基础1.XML文档作用 保存和传输数据 类如&#xff1a; <标题> 标题 </标题> 2.Java的特性优势&#xff08;编译型语言和解释性语言&#xff09; 1.安全 2.面向对象 3.简单性&#xff08;C&#xff09; 4.高性能 5.分布式 6.多线程 7.高并发 8.跨平台 可移植性…

LocalDateTime与LocalDate之间的相互转换

LocalDateTime转换为LocalDate和LocalTime LocalDate转为LocalDateTime

DDD领域驱动之干货 (一)

说道DDD不得不说传统的架构与DDD的架构区别。 传统的架构不外乎就是三层&#xff0c;而在这三层里面又不断的细分&#xff0c;始终没有达到想要的效果&#xff0c;那么为什么当时还是采用三层。 当然在DDD没有提出的时候三层是大多数人的选择。 那么当领域驱动被提出来的时候…

第十三章 常用类(Math 类、Arrays 类、System类、Biglnteger 和BigDecimal 类、日期类)

一、Math 类&#xff08;P481&#xff09; Math 类包含&#xff0c;用于执行基本数学运算的方法&#xff0c;如初等指数、对数、平方根和三角函数。 &#xff08;1&#xff09;abs&#xff1a;绝对值 &#xff08;2&#xff09;pow&#xff1a;求幂 &#xff08;3&#xff09;c…

实体类为什么要用包装类而不用基本类型

eg 基本类型默认为有值的 用包装类不传值得是否默认为空 mybatisplus进行操作时更容易进行是否非空的判断

Asp.Net Core轻量级Aop解决方案:AspectCore

什么是AspectCore Project ? AspectCore Project 是适用于Asp.Net Core 平台的轻量级 Aop(Aspect-oriented programming) 解决方案&#xff0c;它更好的遵循Asp.Net Core的模块化开发理念&#xff0c;使用AspectCore可以更容易构建低耦合、易扩展的Web应用程序。AspectCore使…

指定查找区间,查找学生姓名并显示是否修改成功

首先需要创建两个类&#xff08;面向对象OO的方式实现&#xff09;&#xff1a; 一个是Student&#xff0c;该类主要的代码&#xff1a; String [] names new String [5]; //指定位置查找学生信息public boolean select(int start,int end,String name){boolean flag false;…

去 BAT 面试,总结了这 55 道 MySQL 面试题

转载自 去 BAT 面试&#xff0c;总结了这 55 道 MySQL 面试题 1、一张表&#xff0c;里面有ID自增主键&#xff0c;当insert了17条记录之后&#xff0c;删除了第15,16,17条记录&#xff0c;再把Mysql重启&#xff0c;再insert一条记录&#xff0c;这条记录的ID是18还是15 &am…

使用DotNetty编写跨平台网络通信程序

长久以来,.Net开发人员都非常羡慕Java有Netty这样&#xff0c;高效&#xff0c;稳定又易用的网络通信基础框架。终于微软的Azure团队&#xff0c;使用C#实现的Netty的版本发布。不但使用了C#和.Net平台的技术特点&#xff0c;并且保留了Netty原来绝大部分的编程接口。让我们在使…

Mybatisplus查找数据库中表的策略和id自增策略

默认根据类名向数据库中查找对应的表的名字 加注解自己指定

java中实现客户姓名添加和显示

java中使用带参的方法实现对学生姓名的添加和显示&#xff1a; 首先我们创建一个名为Student类的学生类&#xff0c;由于需要添加多个学生信息&#xff0c;那么我们就先在Student类中声明一个存放学生姓名的数组&#xff1a; String [] names new String[10];然后就是添加学生…

C#码农的大数据之路 - 使用C#编写MR作业

写在前面 从Hadoop出现至今&#xff0c;大数据几乎就是Java平台专属一般。虽然Hadoop或Spark也提供了接口可以与其他语言一起使用&#xff0c;但作为基于JVM运行的框架&#xff0c;Java系语言有着天生优势。而且能找到的与大数据框架如Hadoop等使用介绍的文章也都以Java语言作…

.net Core 生产环境 KestrelServer + Shell 实践

1、背景描述 原项目部署在windwos 服务器下的windwos 服务程序。 2、现已经改版为Linux Centos 下的服务程序。 环境说明&#xff1a; 服务器系统&#xff1a;CentOS 7.0 相关工具&#xff1a;Xshel、Xftp 服务器软件软件&#xff1a;.netcore、 1.安装 CentOS 测试环境…

mysql中ifnull函数

当里面的参数为null时使用第二个参数&#xff0c;否则使用第一个参数

NET Core中使用Irony实现自己的查询语言语法解析器

在之前《在ASP.NET Core中使用Apworks快速开发数据服务》一文的评论部分&#xff0c;.NET大神张善友为我提了个建议&#xff0c;可以使用Compile As a Service的Roslyn为语法解析提供支持。在此非常感激友哥给我的建议&#xff0c;也让我了解了一些Roslyn的知识。使用Roslyn的一…