蓝灯软件数据股份有限公司项目,代码开源。
SqlSugar是一款轻量级的MSSQL ORM ,除了具有媲美ADO的性能外还具有和EF相似简单易用的语法。
学习列表
3、使用SqlSugar实现Join 待更新
4、使用SqlSugar实现分页+分组+多列排序 待更新
5、节点故障如何进行主从调换
一、介简
优点:
1、优越的性能,查询使用 reflection.emit 创建IL语言+委托绑定 然后对该对象进行 cache ,datareader直接赋值给cache对象,高性能拉姆达解析,总体性能媲美 ADO.NET ,查询速度稍慢于datareader但稍快于datatable
2、大量语法糖,拉姆达表达示筛选,新颖的多表查询 ,方便的分页等
3、支持NOLOCK查询,提高性能
4、支持事务
5、内置实体类生成函数,无需使用第三方代码生成器
6、简单好用、例子齐全有问必答。
缺点:
目前只支持MSSQL,以后会全面发展
组成:
sqlSugar是由sqlSugarClientr提供统一调用模式 ,sqlSugarClientr是由5个部分组成
1、自身函数
2、实体生成
3、单表查询
4、多表查询
5、基类函数
如图:
二、使用教程
查询
1、单表或者单视图查询:
通过调用 db.Queryable() 的相关扩展函数 轻松搞定单表查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
using
(SqlSugarClient db =
new
SqlSugarClient(connStr))
//开启数据库连接
{
//查询所有
var
student = db.Queryable<Student>().ToList();
//查询单条
var
single = db.Queryable<Student>().Single(c => c.id == 1);
//取10-20条
var
page1 = db.Queryable<Student>().Where(c => c.id > 10).OrderBy(
"id"
).Skip(10).Take(20).ToList();
//上一句的简化写法,同样取10-20条
var
page2 = db.Queryable<Student>().Where(c => c.id > 10).OrderBy(
"id"
).ToPageList(2, 10);
//查询条数
var
count = db.Queryable<Student>().Where(c => c.id > 10).Count();
//从第2条开始以后取所有
var
skip = db.Queryable<Student>().Where(c => c.id > 10).OrderBy(
"id"
).Skip(2).ToList();
//取前2条
var
take = db.Queryable<Student>().Where(c => c.id > 10).OrderBy(
"id"
).Take(2).ToList();
// Not like
var
notLike = db.Queryable<Student>().Where(c => !c.name.Contains(
"a"
.ToString())).ToList();
// 可以在拉姆达使用 ToString和 Convert,比EF出色的地方
var
convert1 = db.Queryable<Student>().Where(c => c.name ==
"a"
.ToString()).ToList();
var
convert2 = db.Queryable<Student>().Where(c => c.id == Convert.ToInt32(
"1"
)).ToList();
//
var
convert3 = db.Queryable<Student>().Where(c => DateTime.Now > Convert.ToDateTime(
"2015-1-1"
)).ToList();
var
convert4 = db.Queryable<Student>().Where(c => DateTime.Now > DateTime.Now).ToList();
//支持字符串Where 让你解决,更复杂的查询
var
student12 = db.Queryable<Student>().Where(c => 1 == 1).Where(
"id>@id"
,
new
{id=1}).ToList();
}
|
1
2
3
|
//存在记录反回true,则否返回false
bool
isAny100 = db.Queryable<Student>().Any(c => c.id == 100);
bool
isAny1 = db.Queryable<Student>().Any(c => c.id == 1);
|
2、单表高级查询
根据条件查询并分页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/// <summary>
/// 根据条件查询并且分页
/// </summary>
/// <param name="name"></param>
/// <param name="sex"></param>
/// <returns></returns>
public
static
List<Student> GetStudent(
string
name,
string
sex,
int
pageIndex,
int
pageSize,
string
orderFileds,
out
int
pageCount)
{
using
(SqlSugarClient db = SugarDao.GetInstance())
{
var
qable = db.Queryable<Student>();
if
(!
string
.IsNullOrEmpty(name))
{
qable = qable.Where(it => it.name.Contains(name));
}
if
(!
string
.IsNullOrEmpty(sex))
{
qable = qable.Where(it => it.sex == sex);
}
if
(!
string
.IsNullOrEmpty(orderFileds))
//无需担心注入
{
qable = qable.OrderBy(orderFileds);
}
pageCount = qable.Count();
return
qable.ToPageList(pageIndex, pageSize);
}
}
|
新容器转换
1
2
3
4
5
6
7
|
public
List<classNew> GetSelectList(
int
id)
{
using
(SugarDao db =
new
SugarDao())
{
return
db.Queryable<Student>().Where(c=>c.id<10).Select(c =>
new
classNew { newid = c.id, newname = c.name,xx_name=c.name }).ToList();
//不支持匿名类转换,也不建议使用
}
}
|
分组查询
1
2
3
4
5
6
7
|
public
List<SexTotal> GetSexTotal()
{
using
(SugarDao db =
new
SugarDao())
{
return
db.Queryable<Student>().Where(c => c.id < 20).GroupBy(
"sex"
).Select<Student, SexTotal>(
"Sex,Count=count(*)"
).ToList();
}
}
|
1
|
SELECT
Sex,
Count
=
count
(*)
FROM
Student
WHERE
1=1
AND
(id < 20)
GROUP
BY
Sex
--生成结果
|
3、多表查询:
说到多表查询在众多ORM中无论是性能还是功能上都不满意,或者说还不如用SQL,下面是我的创意,放弃了强类型写法,让代码更接近SQL语句编写,让SQL完全可控,也解决了OMR多表的性能问题。
还有ORDERBY、GROUPBY和APPLY等,例子中就不介绍了。
拿EF来比较一下:
EF查询:
1
2
3
4
5
6
7
8
9
10
11
|
var
reval = (
from
s
in
db.Student
join
sc
in
db.School
on
s.sch_id
equals
sc.id
join
sb
in
db.Subject
on
s.id
equals
sb.sid
into
ssb
from
sb2
in
ssb.DefaultIfEmpty()
select
new
{
s.id,
s.name,
s.sch_id,
s.sex
}).Where(c=>c.id>1).Where(c=>c.id>2).OrderBy(c=>c.id).ThenByDescending(c=>c.name).Skip(10).Take(10).ToList();
|
SqlSugar查询:
1
2
3
4
|
db.Sqlable().Form<Student>(
"s"
)
.Join<School> (
"sc"
,
"sc.id"
,
"s.sch_id"
, JoinType.INNER)
.Join<subject>(
"sb"
,
"sb.sid"
,
"s.id"
, JoinType.LEFT).Where(
"s.id>@id1"
).Where(
"s.id>@id2"
)
.SelectToPageList<Models.Student>(
"s.*"
,
"s.id asc,s.name desc"
, 2, 10,
new
{ id1=1,id2=2 });
|
更多的SqlSugar查询:
1
2
3
4
5
6
7
8
9
10
11
|
//表名是字符串写法
List<School> dataList = db.Sqlable()
.Form(
"school"
,
"s"
)
.Join(
"student"
,
"st"
,
"st.id"
,
"s.id"
, JoinType.INNER)
.Join(
"student"
,
"st2"
,
"st2.id"
,
"st.id"
, JoinType.LEFT).Where(
"s.id>100 and s.id<@id"
).SelectToList<School>(
"st.*"
,
new
{ id = 1 });
//多表分页
List<School> dataPageList = db.Sqlable()
.Form<school>(
"s"
)
.Join<student>(
"st"
,
"st.id"
,
"s.id"
, JoinType.INNER)
.Join<student>(
"st2"
,
"st2.id"
,
"st.id"
, JoinType.LEFT).Where(
"s.id>100 and s.id<100"
).SelectToPageList<School>(
"st.*"
,
"s.id"
, 1, 10);
|
子查询加动态拼接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public
List<Student> GetStudent(
int
id,
string
name)
{
int
pageCount = 0;
using
(
var
db = SugarDao.GetInstance())
{
//Form("Student","s")语法优化成 Form<Student>("s")
var
sable = db.Sqlable().Form<Student>(
"s"
).Join<School>(
"l"
,
"s.sch_id"
,
"l.id"
, JoinType.INNER);
if
(!
string
.IsNullOrEmpty(name))
{
sable = sable.Where(
"s.name=@name"
);
}
if
(!
string
.IsNullOrEmpty(name))
{
sable = sable.Where(
"s.id=@id or s.id=100"
);
}
if
(id > 0) {
sable = sable.Where(
"l.id in (select top 10 id from school)"
);
//where加子查询
}
//参数
var
pars =
new
{ id = id, name = name };
pageCount = sable.Count(pars);
return
sable.SelectToList<Student>(
"s.*"
, pars);
}
}
|
4、 使用SQL或者存储过程查询:
为了兼容上面满足不了的情况所以也写了这么个函数以便应急之需
1
2
3
4
5
6
7
8
9
10
|
var
School = db.SqlQuery<School>(
"select * from School"
);
//获取id
var
id = db.SqlQuery<
int
>(
"select top 1 id from School"
).Single();
//存储过程
//var spResult = db.SqlQuery<school>("exec sp_school @p1,@p2", new { p1=1,p2=2 });
//无返回值
db.ExecuteCommand(sql);
|
添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
using
(SqlSugarClient db =
new
SqlSugarClient(connStr))
//开启数据库连接
{
School s =
new
School()
{
name =
"蓝翔"
};
//插入单条
var
id2 = Convert.ToInt32(db.Insert(s));
//插入多条
List<School> sList =
new
List<School>();
sList.Add(s);
var
ids = db.InsertRange(sList);
}
|
修改
1
2
3
4
|
//指定列更新
db.Update<School>(
new
{ name =
"蓝翔2"
}, it => it.id == id);
//整个实体更新,注意主键必需为实体类的第一个属性
db.Update<School>(
new
School { id = id, name =
"蓝翔2"
}, it => it.id == id);
|
删除
1
2
3
4
5
6
7
|
db.Delete<School>(id);
//注意主键必需为实体类的第一个属性
db.Delete<School>(it => it.id > 100);
db.Delete<School>(
new
string
[] {
"100"
,
"101"
,
"102"
});
db.FalseDelete<school>(
"is_del"
, 100);
//假删除
//等同于 update school set is_del=0 where id in(100)<br>
db.FalseDelete<school>(
"is_del"
, it=>it.id==100);
|
更多底层函数
1
2
3
4
5
6
7
8
9
10
|
db.ExecuteCommand(sql);
db.GetDataTable(sql);
db.GetList<Student>(sql);
db.GetSingle<Student>(sql +
" where id=1"
);
using
(SqlDataReader read = db.GetReader(sql)) { }
//事务中一定要释放DataReader
db.GetScalar(sql);
db.GetString(sql);
db.GetInt(sql);
|
实体生成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
using
(SqlSugarClient db =
new
SqlSugarClient(connStr))
//开启数据库连接
{
//根据当前数据库生成所有表的实体类文件 (参数:SqlSugarClient ,文件目录,命名空间)
db.ClassGenerating.CreateClassFiles(db,Server.MapPath(
"~/Models"
),
"Models"
);
//根据表名生成实体类文件
db.ClassGenerating.CreateClassFilesByTableNames(db, Server.MapPath(
"~/Models"
),
"Models"
,
"student"
,
"school"
);
//根据表名生成class字符串
var
str = db.ClassGenerating.TableNameToClass(db,
"Student"
);
//根据SQL语句生成class字符串
var
str2 = db.ClassGenerating.SqlToClass(db,
"select top 1 * from Student"
,
"student"
);
}
|
事务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
using
(SqlSugarClient db =
new
SqlSugarClient(connStr))
//开启数据库连接
{
try
{
//开启事务,可以不使用事务,也可以使用多个事务
db.BeginTran();
//sq1
//sql2
//sql3
}
catch
(Exception ex){
//回滚事务
db.RollbackTran();
throw
ex;
}
}
//关闭数据库连接
|
无锁查询
当IsNoLock设为True时,查询生成的SQL语句表名的后面都会带有With(Nolock)
1
2
3
4
5
6
7
8
9
10
11
|
using
(SqlSugarClient db =
new
SqlSugarClient(connStr))
//开启数据库连接
{
db.IsNoLock =
true
;
//sql xxx with(nolock)
db.IsNoLock =
false
;
//sql xxx
//sql xxx
db.IsNoLock =
true
;
//sql xxx with(nolock)
}
//关闭数据库连接
|
支持多库切换的写法
定义一个sugarDao类来扩展SqlSugar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/// <summary>
/// 扩展SqlSugarClient
/// </summary>
public
class SugarDao
{
//禁止实例化
private SugarDao() {
}
public
static
SqlSugarClient GetInstance()
{
string
connection
=
"Server=.;uid=sa;pwd=sasa;database=SqlSugarTest"
; //这里可以动态根据cookies或session实现多库切换
return
new SqlSugarClient(
connection
);
}
}
|
使用无需传入connectionString
1
2
3
4
5
6
7
|
public
School GetSingleSchool(
int
id)
{
using (SqlSugarClient db = SugarDao.GetInstance())
{
return
db.Queryable<School>().Single(c => c.id == id);
}
}
|
三、性能测试:
10000次
1000次
10000次
.net4.52+EF 6.0+SQL12 以洗耻辱
.NET Framework 4.52+ sql12 +EF6.0 ,EF性能明显上去了,就让它当个冠军吧,我也不去测试了,微软的东西升级后性能无需质疑,在多表查询和添删改方面综合下来也基本平手。
SqlSugar追求的是轻量、上手快、简单易用对SQL的可控性,也希望你能喜欢或者提出您宝贵意见。
V1.0源码下载地址:
http://pan.baidu.com/s/1bnmAXjh
V1.2源码下载地址:
http://pan.baidu.com/s/1jGENyQi
更改内容:
contains查询BUG,SQL拼接BUG
V1.3源码下载地址:
http://pan.baidu.com/s/1kTrRbmR
更改内容:
添加 queryable/sqlable to dataTable
CACHE BUG修复
支持 int?类型这类 nullable类型
此版本稳定,多家公司正在使用
有一点需要声名如果主键不是identity需要写成 insert(obj,false)这不是BUG
主键位置在类中可以任意放无需放第一个
V1.5源码下载地址:
http://pan.baidu.com/s/1pJ8F0dt
更改内容:
1、代码结构优化
2、删除语法需要注意
以前删除
db.Delete<School>(new string[] { "100", "101", "102" });
需要改成下面这种写法
db.Delete<School,string>(new string[] { "100", "101", "102" });
3、添加批量更新
db.Update<School, string>(new { name = "蓝翔2" },new string []{"1","2"});