开源一个基于dotnet standard的轻量级的ORM框架-Light.Data

  还在dotnet framework 2.0的时代,当时还没有EF,而NHibernate之类的又太复杂,并且自己也有一些特殊需求,如查询结果直接入表、水平分表和新增数据默认值等,就试着折腾个轻量点ORM框架,就慢慢有了这个Light.Data,也一直在公司和个人的项目使用,后来陆陆续续也支持了跨数据库并在mono中使用。到了dotnet core来临,也尝试移植,1.0的时候由于类库不完善,效果不理想。2.0的基本完善了,由于个人严重的强迫症和拖延症,一直在折腾细节、写单元测试和磨文档,磨到差不多3.0快来了。。。。

    不说废话了,Light.Data是一个轻量级的基于dotnet standard 2.0的ORM框架, 通过对实体模型类的Attribute或者配置文件进行配置与数据表的对应关系. 使用核心类DataContext对数据表进行CURD的操作.

PM> Install-Package Light.Data
支持数据库
数据库 说明
SqlServer 安装Light.Data.Mssql类库, 支持SqlServer 2008或以上
Mysql 安装Light.Data.Mysql类库, 支持Mysql 5.5或以上
Postgre 安装Light.Data.Postgre类库, 支持Postgre9.3或以上

连接配置

{
"lightData": {
"connections": [
{
"name": "mssql_db",
"connectionString": "...",
"providerName": "Light.Data.Mssql.MssqlProvider, Light.Data.Mssql"
},
{
"name": "mysq_db",
"connectionString": "...",
"providerName": "Light.Data.Mysql.MysqlProvider, Light.Data.Mysql"
}
]
}
}

使用方式

// 直接使用
DataContext context = new DataContext("mssql"); // 创建子类
public class MyDataContext : DataContext
{
public MyDataContext() : base("mssql")
{ }
} // 创建配置子类
public class MyDataContext : DataContext
{
public MyDataContext(DataContextOptions<MyDataContext> options) : base(options)
{ }
} // 直接配置连接字符串和参数 (IServiceCollection)
service.AddDataContext<MyDataContext>(builder => {
builder.UseMssql(connectionString);
builder.SetTimeout();
builder.SetVersion("11.0");
}, ServiceLifetime.Transient); // 默认配置文件配置 (IServiceCollection)
service.AddDataContext<MyDataContext>(DataContextConfiguration.Global, config => {
config.ConfigName = "mssql";
}, ServiceLifetime.Transient);

对象映射

 [DataTable("Te_User", IsEntityTable = true)]
public class TeUser
{
/// <summary>
/// Id
/// </summary>
/// <value></value>
[DataField("Id", IsIdentity = true, IsPrimaryKey = true)]
public int Id
{
get;
set;
} /// <summary>
/// Account
/// </summary>
/// <value></value>
[DataField("Account")]
public string Account
{
get;
set;
} /// <summary>
/// Telephone
/// </summary>
/// <value></value>
[DataField("Telephone", IsNullable = true)]
public string Telephone
{
get;
set;
}
....
}

子表对象关联

在继承类`TeUserAndExtend`中添加一个类型是`TeUserExtend`的公共属性`Extend`, 并加上Attribute`RelationField`, 在查询`TeUserAndExtend`时, 会把关联的`TeUserExtend`数据也一并查出. 并支持一对多的关系
 [DataTable("Te_UserExtend", IsEntityTable = true)]
public class TeUserExtend
{
[DataField("Id", IsIdentity = true, IsPrimaryKey = true)]
public int Id
{
get;
set;
} [DataField("MainId")]
public int MainId
{
get;
set;
} [DataField("Data", IsNullable = true)]
public string Data
{
get;
set;
}
} public class TeUserAndExtend : TeUser
{
[RelationField("Id", "MainId")]
public TeUserExtend Extend
{
get;
set;
}
}

基本操作

  • 基本CURD
  • 批量CUD
  • 支持事务处理
  • 支持数据字段默认值和自动时间戳
  • 支持数据字段读写控制
  • 查询结果指定类或匿名类输出
  • 查询直接插入数据表
 var context = new DataContext();
// 查询单个数据
var item = context.Query<TeUser>().Where(x => x.Id == ).First();
// 查询集合数据
var list = context.Query<TeUser>().Where(x => x.Id > ).ToList();
// 新增数据
var user = new TeUser() {
Account = "foo",
Password = "bar"
};
context.Insert(user);
// 修改数据
user.Password = "bar1";
context.Update(user);
// 删除数据
context.Delete(user);

数据汇总

  • 单列数据直接汇总
  • 多列数据分组汇总
  • 格式化分组字段
  • 汇总数据直接插入数据表
 // 普通汇总
var list = context.Query<TeUser> ()
.Where (x => x.Id >= )
.Aggregate (x => new LevelIdAgg () {
LevelId = x.LevelId,
Data = Function.Count ()
})
.ToList (); // 日期格式化统计
var list = context.Query<TeUser> ()
.Aggtrgate (x => new RegDateFormatAgg () {
RegDateFormat = x.RegTime.ToString("yyyy-MM-dd"),
Data = Function.Count ()
})
.ToList ();

连表查询

  • 多表连接, 支持内连接, 左连接和右连接
  • 支持查询结果和汇总数据连接
  • 连接查询结果指定类或匿名类输出
  • 连接查询结果直接插入数据表
 // 内连接
var join = context.Query<TeUser> ()
.Join<TeUserExtend>((x,y) => x.Id == y.Id); // 统计结果连接实体表
var join = context.Query<TeMainTable>()
.GroupBy(x => new {
MId = x.MId,
Count = Function.Count(),
})
.Join<TeSubTable>((x, y) => x.MId == y.Id);

执行SQL语句

  • 直接使用SQL语句和存储过程
  • 支持对象参数
  • 查询结果指定类或匿名类输出
  • 存储过程支持output参数
 // 普通参数
var sql = "update Te_User set NickName=@P2 where Id=@P1";
var ps = new DataParameter[];
ps[] = new DataParameter("P1", );
ps[] = new DataParameter("P2", "abc");
var executor = context.CreateSqlStringExecutor(sql, ps);
var ret = executor.ExecuteNonQuery(); // 对象参数
var sql = "update Te_User set NickName={nickname} where Id={id}";
var executor = context.CreateSqlStringExecutor(sql, new { nickname = "abc", id = });
var ret = executor.ExecuteNonQuery();

单元测试

项目使用xUnit做单元测试,测试代码地址:https://github.com/aquilahkj/Light.Data2/tree/master/test

每种数据库均有300多组1000多用例的测试,覆盖大部分代码。

性能测试

目前只跟EF Core在同一电脑的Docker上的Sql Server 2017 for linux中做简单的增删改查性能对比测试,代码地址 https://github.com/aquilahkj/OrmTest

1000次的增删改和单条数据查询

共5轮,每轮1000条的增删改和1000条数据查询

EF的测试结果

开源一个基于dotnet standard的轻量级的ORM框架-Light.Data

Light.Data测试结果

开源一个基于dotnet standard的轻量级的ORM框架-Light.Data

从对比看,查询性能两者差不多,新增性能Light.Data稍微占优,批量更新也稍微占优。

另外值得一提的是Postgre,批量增删改性能比Sql Server快2,3倍,看来以后也要好好研究一下。

开源一个基于dotnet standard的轻量级的ORM框架-Light.Data

以上均是非严谨测试,仅供参考。

最后

本文只是简单的介绍,具体使用方法可以查看文档和参考测试用例,如有需要会写具体使用的文章。

Light.Data这个项目这么多年来个人一直维护,也在不断优化,不断成长,但一直养在深闺,好不容易折腾开源也是希望能共享出去,给有需要的朋友多个选择,同时也是给自己这么多年码农的见证。

虽然现在ORM的框架非常非常多,也不是什么热门新鲜事物,但总归是个基础的东西。

如果有朋友喜欢,不妨试试,可以的话,给个Star,十分欢迎意见或建议 :D

上一篇:NET Core写了一个轻量级的Interception框架[开源]


下一篇:20145301《网络对抗》shellcode注入&Return-to-libc攻击深入