这款ORM框架的原版在经历过大概十几个项目的磨合,最近整理了一下,原名字为:ZhCun.Framework ,该框架辗转跟了我去过几家公司,大概从2012年出现第一个版本,当时就为简化数据库操作,从优化SQLHelper,代码生成器,一直到今天个人感觉还算好用的框架;

刚开始写完它的时候是因为当时公司的框架实在太难用(好像是实体为强类型DataTable,实体类太过笨重),但公司因为人员维护及其它的综合考虑只会让我用它做核心业务系统,有一些比较独立的小项目才会用;

这个框架我没有具体去测试过它的性能,但从技术上猜测,应该返回List 会有一定消耗,因为用到反射,但实际项目中很少有大批量的List直接返回给用户查看的;

关于ORM框架,目前有很多人开源的项目都很不错,如果非要为这套框架提出点推荐理由, 勉为其难叫:简单、轻便 吧;编译完之后大概几十K;从程序设计上不太复杂,所以在可读性对于初级程序员来说比较容易,面对核心功能的扩展可能会比较棘手,但我认为还没遇到可扩展的功能就提前做出来,代码设计出空想的东西就属于过度设计;

ORM框架名称:ZhCun.DbCore

目前NuGet 版本分两个,

1.2.0 与 2.2.0 ,其中 2.2.0 为 netstandard2.0 项目,可用于core 项目以及对应的 .Net Freamework 版本(好像是 .net 4.7 吧,具体可百度);1.2.0 在于.net 4.0 基础上开发,代码使用链接共享的;

代码已经托管至“码云” ,https://gitee.com/zhcun/ORM

支持数据库: SQL Server 、SQLite、Oracle、MySQL(因为兼容core的统一版本,OleDb目前暂不支持)

大概介绍一下基本功能及环境:

开发工具:VS 2019
开发框架:.Net 4.0 & netstandard2.0 
支持Lamda,复杂对象查询
新增与更新:支持自动识别赋值字段
支持数据过滤
支持各操作的方法扩展与重载
支持查看执行详情(SQL、耗时 等)
支持实体类扩展自定义属性

 实体类

    实体类中做过一些特殊处理,所以放Model的类库也必须引用 ZhCun.DbCore ,并且继承 EntityBase

实体类分 表(视图)和存储过程两种类型,目前视图和表并没有区分开来,对于框架来说表和视图是一样的;

以下为表的实体类

using System;
using ZhCun.DbCore.Entitys; namespace ZhCun.DbCore.Example.DbModels
{
public partial class TDevice : EntityBase
{
private System.Guid _Id;
/// <summary>
/// Id
/// </summary>
[EntityAttribute(ColumnName = CNId, IsPrimaryKey = true, IsNotNull = true)]
public System.Guid Id
{
get { return _Id; }
set
{
_Id = value;
base.SetFieldChanged(CNId) ;
}
} private System.String _DevName;
/// <summary>
/// DevName
/// </summary>
[EntityAttribute(ColumnName = CNDevName)]
public System.String DevName
{
get { return _DevName; }
set
{
_DevName = value;
base.SetFieldChanged(CNDevName) ;
}
} private System.Guid? _DevType;
/// <summary>
/// DevType
/// </summary>
[EntityAttribute(ColumnName = CNDevType)]
public System.Guid? DevType
{
get { return _DevType; }
set
{
_DevType = value;
base.SetFieldChanged(CNDevType) ;
}
} private System.String _Remark;
/// <summary>
/// Remark
/// </summary>
[EntityAttribute(ColumnName = CNRemark)]
public System.String Remark
{
get { return _Remark; }
set
{
_Remark = value;
base.SetFieldChanged(CNRemark) ;
}
} private System.DateTime? _CreateTime;
/// <summary>
/// CreateTime
/// </summary>
[EntityAttribute(ColumnName = CNCreateTime)]
public System.DateTime? CreateTime
{
get { return _CreateTime; }
set
{
_CreateTime = value;
base.SetFieldChanged(CNCreateTime) ;
}
} private System.DateTime? _ModifyTime;
/// <summary>
/// ModifyTime
/// </summary>
[EntityAttribute(ColumnName = CNModifyTime)]
public System.DateTime? ModifyTime
{
get { return _ModifyTime; }
set
{
_ModifyTime = value;
base.SetFieldChanged(CNModifyTime) ;
}
} private System.Guid? _UserId;
/// <summary>
/// UserId
/// </summary>
[EntityAttribute(ColumnName = CNUserId)]
public System.Guid? UserId
{
get { return _UserId; }
set
{
_UserId = value;
base.SetFieldChanged(CNUserId) ;
}
} #region 字段名的定义
public const string CNId = "Id";
public const string CNDevName = "DevName";
public const string CNDevType = "DevType";
public const string CNRemark = "Remark";
public const string CNCreateTime = "CreateTime";
public const string CNModifyTime = "ModifyTime";
public const string CNUserId = "UserId";
#endregion }
}

  表实体类中当字段只发生过改变会通过 SetFieldChanged方法处理,它会自动判断字段是否赋值,未赋值的字段不会进行增加与修改

实体类声明了 partial 关键字,当需要扩展一些非表字段的属性时建议使用不同的文件操作,这在实际应用中用处比较多;

实体类自动生成的代码中包含字段名的常量,是为了在特殊情况使用sql查询时尽量用该常量来表示字段名,这样当字段设计发生变化更容易修改对应的代码;

当使用扩展或自定义非表字段的属性时需要标记为 IsNotField = true ,如下

[Entity(IsNotField =true)]
public object Tag { set; get; }

其它属性选项:

public class EntityAttribute : Attribute
{
/// <summary>
/// 是否主键
/// </summary>
public bool IsPrimaryKey { set; get; }
/// <summary>
/// 主键是否自动增长
/// </summary>
public bool IsIdentity { set; get; }
/// <summary>
/// 是否非空字段
/// </summary>
public bool IsNotNull { set; get; }
/// <summary>
/// 列名
/// </summary>
public string ColumnName { set; get; }
/// <summary>
/// 默认false为字段属性,如果为true则表示不是一个字段
/// </summary>
public bool IsNotField { set; get; }
}
public class EntiryClassAttribute : Attribute
{
public string TableName { set; get; }
}

存储过程实体类示例:

public class P_AddUser : ProcEntityBase
{
public string LoginName { set; get; } public string LoginPwd { set; get; } public string UserName { set; get; } [ProcParam(ParamDirection = ParameterDirection.Output)]
public string Message { set; get; } [ProcParam(ParamDirection = ParameterDirection.Output)]
public bool Success { set; get; }
}

存储过程实体类特性定义:

/// <summary>
/// 存储过程参数的特性类
/// </summary>
public class ProcParamAttribute : Attribute
{
public ProcParamAttribute()
{
_ParamDirection = ParameterDirection.Input;
_OutSize =;
}
public ProcParamAttribute(ParameterDirection paramDirection)
{
_ParamDirection = paramDirection;
} ParameterDirection _ParamDirection;
/// <summary>
/// 存储过程输出参数的方向类型
/// </summary>
public ParameterDirection ParamDirection
{
get { return _ParamDirection; }
set { _ParamDirection = value; }
}
int _OutSize;
/// <summary>
/// 输出参数的字节数,默认50个字节
/// </summary>
public int OutSize
{
get { return _OutSize; }
set { _OutSize = value; }
}
/// <summary>
/// 是否oracle游标类型
/// </summary>
public bool IsOracleCursor { set; get; }
/// <summary>
/// 参数名,空则使用属性名代表参数名
/// </summary>
public string ParameterName { set; get; }
/// <summary>
/// true表示非存储过程参数
/// </summary>
public bool NotParameter { set; get; }
}

与表的实体类似,具体可查看备注说明;

实体类是ORM的核心部件,大部分操作都依赖实体类;

数据库上下文(DBContext)

核心类 DBContext ,这与其它orm名称可能有冲突,最早参考的EF起的名字,后来也没变过;

虽然可以直接使用DBContext,但还是建议使用继承他的子类,这也可以重写你想改变或注入的业务逻辑;

早先版本的DBContext 是抽象出的接口,后来经过挺长时间的使用,发现并没有其它实现,所以只用了一个核心的类来实现所有的数据库操作了;

以下为DBContext实现功能列表,具体说明可查看源码或着备注说明

 //
// 摘要:
// 数据库操作核心上下文
public class DBContext
{
public DBContext(EmDbType dbType, string connStr); //
// 摘要:
// 数据库操作对象
protected internal IDbHelper DbHelper { get; } //
// 摘要:
// 创建查询条件对象,分页、排序;
public QueryCondition<TEntity> CreateQuery<TEntity>() where TEntity : EntityBase, new();
//
// 摘要:
// 创建sql生成器
public virtual ISqlBuilder CreateSqlBuilder();
//
// 摘要:
// 创建指定参数名称前缀的sql生成器(解决参数名称重复)
public virtual ISqlBuilder CreateSqlBuilder(string paramKey);
//
// 摘要:
// 创建执行的条件对象,不包含分页、排序
public ExecCondition<TEntity> CreateWhere<TEntity>() where TEntity : EntityBase, new();
//
// 摘要:
// 使用执行条件对象,进行删除表达式
//
// 参数:
// execwhere:
// 执行条件对象
//
// 类型参数:
// TEntity:
// 实体对象类型
//
// 返回结果:
// 返回执行结果对象
public virtual ExecResult Delete<TEntity>(ICondition condition) where TEntity : EntityBase, new();
//
// 摘要:
// 根据一个基本的表达式进行删除操作
//
// 参数:
// lamda:
// 表达式
//
// 类型参数:
// TEntity:
// 实体对象类型
//
// 返回结果:
// 返回执行结果对象
public virtual ExecResult Delete<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
//
// 摘要:
// 根据主键删除一条数据
public virtual ExecResult Delete<TEntity>(TEntity entity) where TEntity : EntityBase, new();
//
// 摘要:
// 执行存储过程的方法
//
// 参数:
// procObj:
// 存储过程实体对象
//
// 类型参数:
// ProcEntity:
// ProcedureEntiryBase
//
// 返回结果:
// 返回存储过程结果
public virtual ProcResult ExecProcedure<ProcEntity>(ProcEntity procObj) where ProcEntity : ProcEntityBase, new();
//
// 摘要:
// 根据sql建造起执行sql语句
public virtual ExecResult ExecSql(ISqlBuilder sqlBuilder);
//
// 摘要:
// 新增一条记录
public virtual ExecResult Insert<TEntity>(TEntity entity) where TEntity : EntityBase, new();
//
// 摘要:
// 使用条件对象来进行复杂查询
public virtual QueryResult<TEntity> Query<TEntity>(IQueryCondition condition, ISqlBuilder joinWhereBuilder) where TEntity : EntityBase, new();
//
// 摘要:
// 根据查询对象进行读取数据库,可返回DataTable、List
public virtual QueryResult<TEntity> Query<TEntity>(IQueryCondition condition) where TEntity : EntityBase, new();
//
// 摘要:
// 使用表达式进行普通查询
//
// 参数:
// lamda:
// 表达式
//
// 类型参数:
// TEntity:
// 实体对象类型
public virtual QueryResult<TEntity> Query<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
//
// 摘要:
// 根据一个sqlBuilder来构造where条件的查询
//
// 参数:
// sqlBuilder:
// 可实现参数化查询的sql文本构造器, 不包含 where
public virtual QueryResult<TEntity> Query<TEntity>(ISqlBuilder whereSqlBuilder) where TEntity : EntityBase, new();
//
// 摘要:
// 根据一个sqlBuilder来构造一个完整的查询
//
// 参数:
// sqlBuilder:
// 可实现参数化查询的sql文本构造器
public virtual QueryResult Query(ISqlBuilder sqlBuilder);
public int QueryCount<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
public int QueryCount<TEntity>(IQueryCondition condition) where TEntity : EntityBase, new();
public virtual ScalarResult QueryCountResult<TEntity>(IQueryCondition condition) where TEntity : EntityBase, new();
public virtual ScalarResult QueryCountResult<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
public bool QueryExist<TEntity>(IQueryCondition condition) where TEntity : EntityBase, new();
public bool QueryExist<TEntity>(Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
public virtual ScalarResult QueryMax<TEntity>(Expression<Func<TEntity, object>> selector, IQueryCondition condition) where TEntity : EntityBase, new();
//
// 摘要:
// 执行最大值函数查询
public virtual ScalarResult QueryMax<TEntity>(Expression<Func<TEntity, object>> selector, Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
public virtual ScalarResult QueryMin<TEntity>(Expression<Func<TEntity, object>> selector, Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
public virtual ScalarResult QueryMin<TEntity>(Expression<Func<TEntity, object>> selector, IQueryCondition condition) where TEntity : EntityBase, new();
//
// 摘要:
// 根据一个sqlBuilder 来构造一个完整的查询,用于获取首行首列值
//
// 参数:
// sqlBuilder:
// 可实现参数化查询的sql文本构造器
public virtual ScalarResult QueryScalar(ISqlBuilder sqlBuilder);
public virtual ScalarResult QuerySum<TEntity>(Expression<Func<TEntity, object>> selector, Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
public virtual ScalarResult QuerySum<TEntity>(Expression<Func<TEntity, object>> selector, IQueryCondition condition) where TEntity : EntityBase, new();
//
// 摘要:
// 事务提交
public void TransCommit();
//
// 摘要:
// 事务回滚
public void TransRollback();
//
// 摘要:
// 事务开始
public void TransStart();
//
// 摘要:
// where对象条件更新
public virtual ExecResult Update<TEntity>(TEntity entity, ICondition condition) where TEntity : EntityBase, new();
//
// 摘要:
// 实体对象更新,主键必填
public virtual ExecResult Update<TEntity>(TEntity entity) where TEntity : EntityBase, new();
//
// 摘要:
// lamda表达式更新
public virtual ExecResult Update<TEntity>(TEntity entity, Expression<Func<TEntity, bool>> lamda) where TEntity : EntityBase, new();
//
// 摘要:
// 当使用sqlbuilder(所有实体类执行的Sql都会触发)进行 更新、删除、查询、并指定具体实体类型时在执行前触发, 用于数据过滤的统一处理; 需要子类重写处理过程
protected virtual void BeforeExecSqlBuilder<TEntity>(ISqlBuilder sqlBuilder, EmDbOperation opType) where TEntity : EntityBase, new();
//
// 摘要:
// 创建基于实体形参的where条件的sqlBuider对象(共通封装)
protected virtual ISqlBuilder CreateQuerySqlBuilder<TEntity>() where TEntity : EntityBase, new();
//
// 摘要:
// 使用表达式删除的老大
protected virtual ExecResult DeleteBase<TEntity>(Func<ISqlBuilder, string> whereFun) where TEntity : EntityBase, new();
//
// 摘要:
// 根据sql建造起执行sql语句,加上执行sql where文本
protected virtual ExecResult ExecSql(ISqlBuilder sqlBuilder, string sqlWhere);
//
// 摘要:
// 获取实体对象值,不忽略主键值
protected Dictionary<string, object> GetEntityValue<TEntity>(TEntity entity) where TEntity : EntityBase, new();
//
// 摘要:
// 获取属性值,指定是否忽略自增长主键
protected Dictionary<string, object> GetEntityValue<TEntity>(TEntity entity, bool ignorePK) where TEntity : EntityBase, new();
//
// 摘要:
// 更新的老大
protected virtual ExecResult UpdateBase<TEntity>(TEntity entity, Func<ISqlBuilder, string> whereFun) where TEntity : EntityBase, new();
}

DBContext.cs

新增 (DBContext.Insert)

TUser t = new TUser
{
Id = Guid.NewGuid(),
UserName = "张三",
LoginName = "zhangsan",
LoginPwd = ""
};
DBContext01 db = new DBContext01();
ExecResult r = db.Insert(t);
Console.WriteLine("执行完成,影响 {0} 行", r.RowCount);

执行日志如下:

数据库结果:

未赋值的字段不会生成sql语句;

更新 DBContext.Update

             //根据主键自动条件更新
//只修改名字
var t = new TUser
{
Id = Guid.Parse("A0FCF84C-4EBD-4735-863A-205D8536DA93"),
UserName = "修改后的张三"
};
DBContext01 db = new DBContext01();
ExecResult r = db.Update(t);

Update

这里的ModifyTime 同样被修改了,是因为DBContext01 重写更新的方法,将字段进行默认赋值;

删除 DBContext.Delete (按主键)

             //默认按主键条件删除
var t = new TUser();
t.Id = Guid.Parse("84DF3116-27A6-44E3-9E07-403F8B744932");
DBContext01 db = new DBContext01();
var r = db.Delete(t);
Console.WriteLine("执行完成,影响 {0} 行", r.RowCount);

当主键被赋值后默认使用主键进行删除

删除 DBContext.Delete (lamda 表达式条件)

            //指定条件删除
DBContext01 db = new DBContext01();
var r = db.Delete<TUser>(s => s.UserName == "张三");
Console.WriteLine("执行完成,影响 {0} 行", r.RowCount);

删除 DBContext.Delete (where对象条件)

             DBContext01 db = new DBContext01();
var where = db.CreateWhere<TUser>();
Guid id1 = Guid.Parse("A0FCF84C-4EBD-4735-863A-205D8536DA93");
where.WhereAnd(s => s.WEx_In(s.Id, id1));
var r = db.Delete<TUser>(where);
Console.WriteLine("执行完成,影响 {0} 行", r.RowCount);

事务

             DBContext01 db = new DBContext01();
try
{
db.TransStart();
TUser user = new TUser();
user.Id = Guid.NewGuid();
user.UserName = "王五";
user.LoginName = "wangwu";
db.Insert(user); TDevice dev = new TDevice();
dev.Id = Guid.NewGuid();
dev.DevName = "笔记本";
db.Insert(dev); db.TransCommit();
Console.WriteLine("事务执行完成");
}
catch (Exception ex)
{
db.TransRollback();
Console.WriteLine(ex.Message);
}

查询(DBContext.Query)lamda 表达式 全部

             //查询所有数据
var db = new DBContext01();
var r = db.Query<TUser>(s => true);
var rList = r.ToList();

查询(DBContext.Query)lamda 表达式 

             //使用lamad表达式查询
var db = new DBContext01();
var r = db.Query<TUser>(s => s.UserName == "张三");
var rList = r.ToList();
Common.PrintList(rList);

查询(DBContext.Query)-  query对象

             //使用query对象查询
var db = new DBContext01();
var query = db.CreateQuery<TUser>();
query.WhereAnd(s => s.WEx_Like(s.UserName, "%张三%"));
query.WhereOr(s => s.Email != null);
var r = db.Query<TUser>(query);
var rList = r.ToList();

查询(DBContext.Query)-  query对象 分页查询

             var db = new DBContext01();
//使用分页查询
var query = db.CreateQuery<TUser>();
query.PageNo = ;
query.PageSize = ;
query.WhereAnd(s => s.UserName != null).OrderBy(s => s.UserName);
var r = db.Query<TUser>(query);
var rList = r.ToList();

查询(DBContext.Query) - SQL语句条件查询List

             var db = new DBContext01();
//使用sql语句的where查询
var sqlBuilder = db.CreateSqlBuilder();
//使用参数化查询
sqlBuilder.AddSQLText("LoginName in ({0},{1})",
sqlBuilder.AddParam("zhangsan"),
sqlBuilder.AddParam("lisi"));
var r = db.Query<TUser>(sqlBuilder);
var rList = r.ToList();

查询(DBContext.Query) - SQL语句查询DataTable

             var db = new DBContext01();
//使用sql语句查询得到DataTable
db.CreateSqlBuilder();
var sqlBuilder = db.CreateSqlBuilder();
//使用参数化查询
sqlBuilder.AddSQLText("select * from TUser where LoginName in ('zhangsan','lisi')");
var r = db.Query(sqlBuilder);
var data = r.ToDataTable();

注意:当使用Sql语句查询只能得到 DataTable

存储过程(DBContext.ExecProcedure)- 执行

             P_AddUser p = new P_AddUser();
p.LoginName = "张存";
p.LoginPwd = "";
p.UserName = "";
var db = new DBContext01();
var r = db.ExecProcedure(p);
r.ExecProc();

存储过程(DBContext.ExecProcedure)-  查询

             P_GetUser p = new P_GetUser();
var db = new DBContext01();
var r = db.ExecProcedure(p);
var rList = r.ToList<TUser>();

数据过滤及默认赋值 DBContext 重写

     class DBContext01 : DBContextBase
{
Guid _loginUserId; public void SetLoginUserId(Guid loginUserId)
{
_loginUserId = loginUserId;
} /// <summary>
/// 根据属性名设置对象的属性值
/// </summary>
public static void SetPropertyValue<T>(T obj, string pName, object pValue) where T : class, new()
{
Type t = typeof(T);
PropertyInfo pInfo = t.GetProperty(pName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance); if (pInfo != null && pInfo.CanWrite)
{
if (pValue == null || DBNull.Value.Equals(pValue) || Guid.Empty.Equals(pValue))
{
return;
}
string pTypeName = pInfo.PropertyType.Name.ToUpper();
if (pTypeName == "GUID")
{
pValue = new Guid(pValue.ToString());
}
else
{
pValue = Convert.ChangeType(pValue, pInfo.PropertyType);
}
pInfo.SetValue(obj, pValue, null);
}
}
/// <summary>
/// 结果完成的处理方法,如:写入日志
/// </summary>
protected override void ResultFinish(BaseResult result)
{
//Task.Factory.StartNew(() => { });
var sql = result.SqlContent;
Console.WriteLine("执行标记:{0}", result.ResultMark);
Console.WriteLine("SQL:{0}", sql);
Console.WriteLine("耗时:{0}", result.ExecInterval);
Console.WriteLine("所影响行:{0}", result.RowCount);
Console.WriteLine();
}
public override ExecResult Insert<TEntity>(TEntity entity)
{
//如果该实体有“UserId”字段那么缺省赋值为:_loginUserId 值
SetPropertyValue(entity, "UserId", _loginUserId);
//如果字段Id没有被赋值,则赋值默认字段为新的Guid
if (!entity.IsChangeField("Id"))
{
SetPropertyValue(entity, "Id", Guid.NewGuid());
}
//如果实体有“CreateTime” 字段,设置为当前时间
SetPropertyValue(entity, "CreateTime", DateTime.Now);
return base.Insert<TEntity>(entity);
}
protected override ExecResult UpdateBase<TEntity>(TEntity entity, Func<ISqlBuilder, string> whereFun)
{
SetPropertyValue(entity, "ModifyTime", DateTime.Now);
return base.UpdateBase<TEntity>(entity, whereFun);
}
protected override void BeforeExecSqlBuilder<TEntity>(ISqlBuilder sqlBuilder, EmDbOperation opType)
{
//user 没有UserId 字段加上过滤
if (typeof(TEntity) == typeof(TUser))
{
return;
}
//判断当前执行方法是否指定了过滤条件
if (QueryFilterHelper.IsFilter())
{
//追加sql文本,同时会把所有已有条件加上括号,并加上and符号
sqlBuilder.AddSqlTextByGroup(" UserId = {0}", sqlBuilder.AddParam(_loginUserId));
}
}
}

数据过滤用于实现当不同用户、角色、部门 等 查询条件的全局处理;

今天先写这么多吧,最后的几个小节说明有点少;

共享出来也是为了进步,也希望会有人指出不足以改正缺陷;

前几天翻过几篇.Net 比较好的ORM框架,有很多轻量级的都已经很成熟了,功能也很全面;

个人认为现在公司选择ORM框架分两种:1. 用自己的ORM,便于处理业务上的个性需求。2.用官网常用的ORM框架(如:EF),大众货,功能全,很多“学生”时代都已经纳入“课本”的学习标准;

不管怎么样,也希望这个开源项目能对新手或者打算写自己ORM框架的人有所帮助

最新文章

  1. iOS动态部署之RSA加密传输Patch补丁
  2. Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作
  3. ✡ leetcode 158. Read N Characters Given Read4 II - Call multiple times 对一个文件多次调用read(157题的延伸题) --------- java
  4. Python pass语句作用与用法
  5. Matlab boxplot for Multiple Groups(多组数据的箱线图)
  6. C#_Fileuploadify_notMvc
  7. [Java I/O] TextFile 工具类
  8. 关于html标签元素的data-*属性
  9. leetcode[55] Merge Intervals
  10. Scope and Namespace
  11. Price Channel Breakout 交易系统简价及源码
  12. springIoC的理解01
  13. DIV+CSS详解
  14. 2018-08-14 中文代码之Spring Boot实现简单REST服务
  15. 网页发起qq临时会话
  16. python_高级特征
  17. HTML编码规则
  18. Word Ladder - LeetCode
  19. 集合之HashMap
  20. 基于Neutron的Kubernetes SDN实践经验之谈

热门文章

  1. MySQL Authentication plugin &#39;caching_sha2_password&#39; cannot be loaded
  2. HttpClient测试框架
  3. jmeter 参数化4_Function Helper中的函数
  4. Java二级练习试题一
  5. checked属性 详解
  6. Java基本数据类型及所占字节大小
  7. Web项目改名的带来的404not found问题
  8. 在Android中实现一个简易的Http服务器
  9. JS中数据结构之字典
  10. BUUCTF | SQL COURSE 1