这款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框架的人有所帮助

发布并开源自己的一款 基于.Net 4.0 及 netstandard2.0 的 ORM 框架的更多相关文章

  1. 推荐一款基于XNA的开源游戏引擎《Engine Nine》

    一.前沿导读 XNA是微软基于.Net部署的下一代3D/2D游戏开发框架,其实XNA严格来说类似下一代的DirectX,当然不是说XNA会取代DirectX,但是基于XNA我们对于面向XBOX360, ...

  2. Linux 获得了其首款基于 RISC-V 的多核开源处理器

    去年,硅谷创业公司 SiFive 发布了首款开源 SoC(片上系统 System on a Chip),命名为 Freeform Everywhere 310.现在,该公司从嵌入式系统领先一步,发布了 ...

  3. 分享一款基于aui框架的图文发布界面

    本文出自APICloud官方论坛, 感谢论坛版主 川哥哥 的分享. 分享一款基于aui框架的图文发布界面,可以添加多张图可以删除,类似qq空间发布说说,没做服务器后端,只演示前端操作.需要用到UIMe ...

  4. rtvue-lowcode:一款基于uniapp框架和uview组件库的开源低代码开发平台

    rtvue-lowcode低代码开发平台 rtvue-lowcode一款基于uniapp框架和uview组件库的低代码开发平台,项目提供可视化拖拽编辑器,采用MIT开源协议,适用于app.小程序等项目 ...

  5. QQ 腾讯QQ(简称“QQ”)是腾讯公司开发的一款基于Internet的即时通信(IM)软件

    QQ 编辑 腾讯QQ(简称“QQ”)是腾讯公司开发的一款基于Internet的即时通信(IM)软件.腾讯QQ支持在线聊天.视频通话.点对点断点续传文件.共享文件.网络硬盘.自定义面板.QQ邮箱等多种功 ...

  6. 10款基于jquery的web前端特效及源码下载

    1.jQuery时间轴插件:jQuery Timelinr 这是一款可用于展示历史和计划的时间轴插件,尤其比较适合一些网站展示发展历程.大事件等场景.该插件基于jQuery,可以滑动切换.水平和垂直滚 ...

  7. nakadi 一款基于kafka 的http event broker

    nakadi 是zalando 开源的一款基于kafka 的event broker ,我们可以方便的使用http 协议进行操作 支持一些特性: stream 操作,我们可以流的方式订阅event e ...

  8. 目前几款基于html5的前端框架:如Bootstrap、Foundation、Semantic UI 、Amaze UI

    Bootstrap是由Twitter在2011年8月推出的开源WEB前端框架,集合CSS 和HTML,使用了最新的浏览器技术,为快速WEB开发提供了一套前端工具包,包括布局.网格.表格.按钮.表单.导 ...

  9. Processon 一款基于HTML5的在线作图工具

    CSDN的蒋涛不久前在微博上评价说ProcessOn是web版的visio,出于好奇私下对ProcessOn进行了一番研究.最后发现无论是在用户体验上,还是在技术上,ProcessOn都比微软的Vis ...

随机推荐

  1. jsp中引入js文件缓存问题解决

    加上版本UUID <script charset="utf-8" src="${basePath}js/souke/soukegalist.js?v=<%=U ...

  2. python已处理的异常

    字符串比较中,如果一个字符串有内容,另一个没有内容,python不会报错,而是认为两个字符串不相同如 a=" b="" if a[4:5]==b[4:5]: print( ...

  3. springBoot 连接数据库

    心得:1.先添加依赖. 2.在application.yml文件中创建mybatis的连接,与项目连接起来. 3.application.yml文件中可以自行配置服务器的端口,配置mybatis的路径 ...

  4. hihocoder 1014: Trie树(Trie树模板题)

    题目链接 #include<bits/stdc++.h> using namespace std; ; struct T { int num; T* next[]; T() { num=; ...

  5. Redis缓存在django中的配置

    django  settings中的配置 # 缓存 CACHES = { "default": { "BACKEND": "django_redis. ...

  6. 4412 Linux设备总线

    总线_设备_驱动注册流程详解 注册流程图 • 设备一般都需要先注册,才能注册驱动– 现在越来越多的热拔插设备,反过来了.先注册驱动,设备来了再注册 设备 • 本节使用的命令– 查看总线的命令#ls / ...

  7. webpack使用的补充

    1.分离生产环境和开发环境的wepack.config.js 我们可以将生产环境和开发环境中的配置分离为两个不同的文件,并且还维护一个共同的配置文件 common,可以通过 webpack.merge ...

  8. php简易分词

    http://www.xunsearch.com/ 示例 http://www.xunsearch.com/scws/demo/v48.php

  9. LOJ 2997 「THUSCH 2017」巧克力——思路+随机化+斯坦纳树

    题目:https://loj.ac/problem/2977 想到斯坦纳树.但以为只能做 “包含一些点” 而不是 “包含一些颜色” .而且不太会处理中位数. 其实 “包含一些颜色” 用斯坦纳树做也和普 ...

  10. Linux 删除特殊文件名的文件

    1.文件名含有特殊字符: 1) 执行 ls -i 命令 ,文件前面会出现一个数字,这个数字是文件的节点号 2) 使用find命令删除 find ./ -inum 节点号 -delete 2.文件名是以 ...