开源一个基于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或以上 |
使用文档: https://aquilahkj.github.io/Light.Data.Site/#/zh-cn/
Github: https://github.com/aquilahkj/Light.Data2
连接配置
{
"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;
}
....
}
子表对象关联
[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的测试结果

Light.Data测试结果

从对比看,查询性能两者差不多,新增性能Light.Data稍微占优,批量更新也稍微占优。
另外值得一提的是Postgre,批量增删改性能比Sql Server快2,3倍,看来以后也要好好研究一下。

以上均是非严谨测试,仅供参考。
最后
本文只是简单的介绍,具体使用方法可以查看文档和参考测试用例,如有需要会写具体使用的文章。
Light.Data这个项目这么多年来个人一直维护,也在不断优化,不断成长,但一直养在深闺,好不容易折腾开源也是希望能共享出去,给有需要的朋友多个选择,同时也是给自己这么多年码农的见证。
虽然现在ORM的框架非常非常多,也不是什么热门新鲜事物,但总归是个基础的东西。
如果有朋友喜欢,不妨试试,可以的话,给个Star,十分欢迎意见或建议 :D
开源一个基于dotnet standard的轻量级的ORM框架-Light.Data的更多相关文章
- 推荐一个适用于SpringBoot项目的轻量级HTTP客户端框架,快来试试它!
在SpringBoot项目直接使用okhttp.httpClient或者RestTemplate发起HTTP请求,既繁琐又不方便统一管理.因此,在这里推荐一个适用于SpringBoot项目的轻量级HT ...
- 基于java注解实现自己的orm框架
ORM即Object Relation Mapping,Object就是对象,Relation就是关系数据库,Mapping映射,就是说Java中的对象和关系数据库中的表存在一种对应关系. 现在常见的 ...
- eShopOnContainers 是一个基于微服务的.NET Core示例框架
找到一个好的示例框架很难,但不是不可能.大多数是小型Todo风格的应用程序,通常基于SimpleCRUD.值得庆幸的是,Microsoft已经为eShopOnContainers创建了一个基于微服务的 ...
- 亲手搭建一个基于Asp.Net WebApi的项目基础框架1
目标:教大家搭建一个简易的前后端分离的项目框架. 目录: 1:关于项目架构的概念 2:前后端分离的开发模式 3:搭建框架的各个部分 这段时间比较闲,所以想把之前项目里用到的一些技术写到博客里来,分享给 ...
- 亲手搭建一个基于Asp.Net WebApi的项目基础框架4
实现目的:配置website端与服务端对接 1:配置好各项配置文件 2:server端编写接口客户端调用 1.1首先配置文件有log4的配置文件,有config的配置文件,还有服务列表的配置文件 首先 ...
- 开源一个基于天天团购的团购app
可能大家都知道天天团购开源系统,一个做团购的开源项目很赞,前些日子做了基于天天团购系统做的团购客户端和移动端服务器!源代码放出,有了解的可以看看,希望收益! 先说服务器:app的服务器,基于天天团购的 ...
- C# 开源一个基于 yarp 的 API 网关 Demo,支持绑定 Kubernetes Service
关于 Neting 刚开始的时候是打算使用微软官方的 Yarp 库,实现一个 API 网关,后面发现坑比较多,弄起来比较麻烦,就放弃了.目前写完了查看 Kubernetes Service 信息.创建 ...
- [安卓] 12、开源一个基于SurfaceView的飞行射击类小游戏
前言 这款安卓小游戏是基于SurfaceView的飞行射击类游戏,采用Java来写,没有采用游戏引擎,注释详细,条理比较清晰,适合初学者了解游戏状态转化自动机和一些继承与封装的技巧. 效果展示 ...
- 开源一个基于nio的java网络程序
因为最近要从公司离职,害怕用nio写的网络程序没有人能看懂(或许是因为写的不好吧),就调整成了mina(这样大家接触起来非常方便,即使没有socket基础,用起来也不难),所以之前基于nio写的网络程 ...
随机推荐
- 通过Java反射做实体查询
我们在使用hibernate的时候,查询的时候都会和实体中的一些字段相结合去查询,当然字段少了,还算是比较简单,当字段多了,就不那么容易了,所以就自己写了个方法,根据实体中的字段信息去查询,废话不多说 ...
- Intel processor brand names-Xeon,Core,Pentium,Celeron----Quark
http://en.wikipedia.org/wiki/Intel_Quark Intel Quark From Wikipedia, the free encyclopedia Intel ...
- Python 学习资料分享
有同学需要学习 Python,确实,随着人工智能被炒的火热,再加上大数据时代,作为程序员的我们,怎么可能坐得住,必须尝尝鲜,给自己增加一项技能,增加自己的竞争了. 内容定位 这方面的学习资料比较多,本 ...
- BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)
3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S ...
- HDU 6044 Limited Permutation 读入挂+组合数学
Limited Permutation Problem Description As to a permutation p1,p2,⋯,pn from 1 to n, it is uncomplica ...
- Educational Codeforces Round 9 E. Thief in a Shop NTT
E. Thief in a Shop A thief made his way to a shop. As usual he has his lucky knapsack with him. Th ...
- HBase在滴滴出行的应用场景和最佳实践
摘要: 主要介绍了HBase和Phoenix在滴滴内部的一些典型案例.文章已在CSDN极客头条和<程序员>杂志发表,应朋友邀请,分享到云栖社区,希望给大家带来启发和帮助. 背景 对接业务类 ...
- Comparing Random and Sequential Access in Disk and Memory
The Pathologies of Big Data - ACM Queue https://queue.acm.org/detail.cfm?id=1563874
- mvn_action
validate(验证): 验证项目正确,并且所有必要信息可用. compile(编译): 编译项目源码 test(测试): 使用合适的单元测试框架测试编译后的源码. package(打包): 源码编 ...
- 【POJ 1159】Palindrome
[POJ 1159]Palindrome 近期各种题各种奇葩思路已经司空见惯了...又新出个滚动数组= = 该题另一点须要知道 最少须要补充的字母数 = 原序列S的长度 - S和S'的最长公共子串长度 ...