【纯技术贴】.NETStandardFreeSqlv0.0.9功能预览

编程

年关将至,首页技术含量文章真是越来越少,理解大家盼着放假过年,哥们我何尝不是,先给大家拜个早年。

兄弟我从11月底发了神经,开启了 ORM 功能库的开发之旅,历时两个月编码和文档整理,目前预览版本更新到 v0.0.9 仍是一个初级版本,怎奈今天把 wiki 文档更新到一半,突然想写一篇文章提前向大家介绍项目。

快过年还逼着您来了解新的技术,实在是抱歉了。介绍一下自己,有一些朋友可能知道我本人,我经常会在群里放开源项目,比如 dotnetGen、csredis 等,反感之余仍然希望可以真的帮助到有需要的人,CSRedisCore 正是本人维护的项目,本文介绍的不是它。

简单点介绍,FreeSql 是一个NETStandard ORM 功能库,采用 MIT 开源协议部署在 github。

它实现了的功能特性

  • [x] CodeFirst 迁移。
  • [x] DbFirst 从数据库导入实体类,支持三种模板生成器。
  • [x] 采用 ExpressionTree 高性能读取数据。
  • [x] 类型映射深入支持,比如pgsql的数组类型。
  • [x] 支持丰富的表达式函数。
  • [x] 支持导航属性查询,和延时加载。
  • [x] 支持同步/异步数据库操作方法,丰富多彩的链式查询方法。
  • [x] 支持事务。
  • [x] 支持读写分离。
  • [x] 支持多种数据库,MySql/SqlServer/PostgreSQL/Oracle/Sqlite。

快速开始

var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + 

"Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10";

IFreeSql fsql = new FreeSql.FreeSqlBuilder()

.UseConnectionString(FreeSql.DataType.MySql, connstr)

.UseSlave("connectionString1", "connectionString2") //使用从数据库,支持多个

.UseMonitorCommand(

cmd => Console.WriteLine(cmd.CommandText), //监听SQL命令对象,在执行前

(cmd, traceLog) => Console.WriteLine(traceLog)) //监听SQL命令对象,在执行后

.UseLogger(null) //使用日志,不指定默认输出控制台 ILogger

.UseCache(null) //使用缓存,不指定默认使用内存 IDistributedCache

.UseAutoSyncStructure(true) //自动同步实体结构到数据库

.UseSyncStructureToLower(true) //转小写同步结构

.UseLazyLoading(true) //延时加载导航属性对象,导航属性需要声明 virtual

.Build();

定义实体

可从现有数据库生成实体模型,提供 IDbFirst 生成实体模型。或者手动创建模型,基于模型创建或修改数据库,提供 ICodeFirst 同步结构的 API(甚至可以做到开发阶段自动同步)。

[Table(Name = "tb_topic")]

class Topic {

[Column(IsIdentity = true, IsPrimary = true)]

public int Id { get; set; }

public int Clicks { get; set; }

public int TestTypeInfoGuid { get; set; }

public TestTypeInfo Type { get; set; }

public string Title { get; set; }

public DateTime CreateTime { get; set; }

}

class TestTypeInfo {

public int Guid { get; set; }

public int ParentId { get; set; }

public TestTypeParentInfo Parent { get; set; }

public string Name { get; set; }

}

class TestTypeParentInfo {

public int Id { get; set; }

public string Name { get; set; }

}

ISelect<Topic> select => fsql.Select<Topic>();

查询

普通查询

var sql = select.Where(a => a.Id == 10).ToSql();

///SELECT ... FROM `tb_topic` a WHERE (a.`Id` = 10)

sql = select.Where(a => a.Id == 10 && a.Id > 10 || a.Clicks > 100).ToSql();

///SELECT ... FROM `tb_topic` a WHERE (a.`Id` = 10 AND a.`Id` > 10 OR a.`Clicks` > 100)

sql = select.Where(a => new []{1,2,3}.Contains(a.Id)).ToSql();

//SELECT ... FROM `tb_topic` a WHERE (a.`Id` in (1,2,3))

每页20条数据,查询第1页

var sql = select.Page(1, 20).ToSql();

///SELECT ... FROM `tb_topic` a LIMIT 0,20

利用导航属性联表

sql = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToSql();

//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime`

//FROM `tb_topic` a

//LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`

sql = select

.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid)

.LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId).ToSql();

//SELECT ...

//FROM `tb_topic` a

//LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`

//LEFT JOIN `TestTypeParentInfo` a__Type__Parent ON a__Type__Parent.`Id` = a__Type.`ParentId`

子表 Exists 查询

var sql2222 = select.Where(a => select.Where(b => b.Id == a.Id).Any()).ToList();

// SELECT ... FROM `xxx` a WHERE (exists(SELECT 1 FROM `xxx` b WHERE (b.`Id` = a.`Id`)))

//两级相同的子表查询

sql2222 = select.Where(a =>

select.Where(b => b.Id == a.Id && select.Where(c => c.Id == b.Id).Where(d => d.Id == a.Id).Where(e => e.Id == b.Id)

.Offset(a.Id)

.Any()

).Any()

).ToList();

// SELECT ... FROM `xxx` a WHERE (exists(SELECT 1 FROM `xxx` b WHERE (b.`Id` = a.`Id` AND exists(SELECT 1 FROM `xxx` c WHERE (c.`Id` = b.`Id`) AND (c.`Id` = a.`Id`) AND (c.`Id` = b.`Id`) limit 0,1)) limit 0,1))

查找今天创建的数据

select.Where(a => a.CreateTime.Date == DateTime.Now.Date).ToSql();

支持功能丰富的表达式函数解析,包括(字符串、日期、时间、数学、类型转换)等函数,方便程序员在不了解数据库函数的情况下编写代码。这是非常特色的功能之一,深入细化函数解析尽量做到满意,所支持的类型基础都可以使用对应的表达式函数,例如 日期、字符串、IN查询、数组(PostgreSQL的数组)、字典(PostgreSQL HStore)等等。

获得查询返回的数据

采用 ExpressionTree 优化读取速读,如果懂技术的你一定知道 .NETCore 技术下除了原生代码,最快就是 Emit 和 ExpressionTree。项目在初期使用的反射+缓存,虽然 .NETCore 优化了反射性能,但经过与Dapper性能测试对比之后,发现仍然有一定差距,改成 ExpresstionTree 后才与 Dapper 性能相当。FreeSql 支持的类型较多,现实 ExpressionTree 的复杂度较大,有兴趣的朋友可以翻阅源代码。

返回单条记录

Topic t1 = select.Where(a => a.Id == 1).ToOne();

FreeSql有两个约定,ToOne 永远返回 null 或 有数据的实体对象,ToList 永远返回非 null 的 List<实体类型>

返回 List

List<Topic> t1 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList();

返回 List + 导航属性的数据

List<Topic> t2 = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToList();

//此时会返回普通字段 + 导航对象 Type 的数据

指定字段返回

//返回一个字段

List<int> t3 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList(a => a.Id);

//返回匿名类

List<匿名类> t4 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList(a => new { a.Id, a.Title });

//返回元组

List<(int, string)> t5 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList<(int, string)>("id, title");

//返回SQL字段

List<匿名类> t6 = select.Where(a => a.Id > 0).Skip(100).Limit(200)

.ToList(a => new {

a.Id,

a.Title,

cstitle = "substr(a.title, 0, 2)", //将 substr(a.title, 0, 2) 作为查询字段

csnow = Convert.ToDateTime("now()"), //将 now() 作为查询字段

//奇思妙想:怎么查询开窗函数的结果

});

//返回更为复杂的结构

List<匿名类> t7 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s

.InnerJoin(a => a.TypeGuid == b.Guid)

.LeftJoin(a => c.Id == b.ParentId)

.Where(a => b.Name != "xxx")).ToList((a, b, c) => new {

a.Id,

a.Title,

a.Type,

ccc = new { a.Id, a.Title },

tp = a.Type,

tp2 = new {

a.Id,

tp2 = a.Type.Name

},

tp3 = new {

a.Id,

tp33 = new {

a.Id

}

}

});

执行SQL返回数据

class xxx {

public int Id { get; set; }

public string Path { get; set; }

public string Title2 { get; set; }

}

List<xxx> t8 = fsql.Ado.Query<xxx>("select * from song");

List<(int, string ,string)> t7 = fsql.Ado.Query<(int, string, string)>("select * from song");

List<dynamic> t9 = fsql.Ado.Query<dynamic>("select * from song");

CodeFirst

支持 CodeFirst 迁移结构至数据库,这应该是(O/RM)必须标配的一个功能。

与其他(O/RM)不同FreeSql支持更多的数据库特性,而不只是支持基础的数据类型,这既是优点也是缺点,优点是充分利用数据库特性辅助开发,缺点是切换数据库变得困难。不同程序员的理念可能不太一致,作为功能库FreeSql支持到了极致,至于是否使用是项目组技术衡量的另一个问题。

尽管多种数据库适配逻辑非常复杂,FreeSql始终秉承优化程序开发习惯的原则尽量去现实,中间碰到了一些非技术无法攻克的难题,比如数据库的自定义类型,和实体类本身就是一种冲突,为了减少使用成本,诸如此类的数据库功能没有得到支持。

除了在实体上标注特性,也支持实体以外配置

fsql.CodeFirst

.ConfigEntity<TestFluenttb1>(a => {

a.Name("xxdkdkdk1").SelectFilter("a.Id22 > 0");

a.Property(b => b.Id).Name("Id22").IsIdentity(true);

a.Property(b => b.name).DbType("varchar(100)").IsNullable(true);

})

.ConfigEntity<TestFluenttb2>(a => {

a.Name("xxdkdkdk2").SelectFilter("a.Idx > 0");

a.Property(b => b.Id).Name("Id22").IsIdentity(true);

a.Property(b => b.name).DbType("varchar(100)").IsNullable(true);

});

类型映射

csharp

MySql

SqlServer

PostgreSQL

Oracle

Sqlite

bool | bool?

bit(1)

bit

bool

number(1)

boolean

sbyte | sbyte?

tinyint(3)

smallint

int2

number(4)

smallint

short | short?

smallint(6)

smallint

int2

number(6)

smallint

int | int?

int(11)

int

int4

number(11)

integer

long | long?

bigint(20)

bigint

int8

number(21)

integer

byte | byte?

tinyint(3) unsigned

tinyint

int2

number(3)

int2

ushort | ushort?

smallint(5) unsigned

int

int4

number(5)

unsigned

uint | uint?

int(10) unsigned

bigint

int8

number(10)

decimal(10,0)

ulong | ulong?

bigint(20) unsigned

decimal(20,0)

numeric(20,0)

number(20)

decimal(21,0)

double | double?

double

float

float8

float(126)

double

float | float?

float

real

float4

float(63)

float

decimal | decimal?

decimal(10,2)

decimal(10,2)

numeric(10,2)

number(10,2)

decimal(10,2)

Guid | Guid?

char(36)

uniqueidentifier

uuid

char(36 CHAR)

character(36)

TimeSpan | TimeSpan?

time

time

time

interval day(2) to second(6)

bigint

DateTime | DateTime?

datetime

datetime

timestamp

timestamp(6)

datetime

DateTimeOffset | DateTimeOffset?

-

-

datetimeoffset

timestamp(6) with local time zone

-

Enum | Enum?

enum

int

int4

number(16)

mediumint

FlagsEnum | FlagsEnum?

set

bigint

int8

number(32)

bigint

byte[]

varbinary(255)

varbinary(255)

bytea

blob

blob

string

varchar(255)

nvarchar(255)

varchar(255)

nvarchar2(255)

nvarchar(255)

MygisPoint

point

-

-

-

-

MygisLineString

linestring

-

-

-

-

MygisPolygon

polygon

-

-

-

-

MygisMultiPoint

multipoint

-

-

-

-

MygisMultiLineString

multilinestring

-

-

-

-

MygisMultiPolygon

multipolygon

-

-

-

-

BitArray

-

-

varbit(64)

-

-

NpgsqlPoint

-

-

point

-

-

NpgsqlLine

-

-

line

-

-

NpgsqlLSeg

-

-

lseg

-

-

NpgsqlBox

-

-

box

-

-

NpgsqlPath

-

-

path

-

-

NpgsqlPolygon

-

-

polygon

-

-

NpgsqlCircle

-

-

circle

-

-

(IPAddress Address, int Subnet)

-

-

cidr

-

-

IPAddress

-

-

inet

-

-

PhysicalAddress

-

-

macaddr

-

-

NpgsqlRange<int>

-

-

int4range

-

-

NpgsqlRange<long>

-

-

int8range

-

-

NpgsqlRange<decimal>

-

-

numrange

-

-

NpgsqlRange<DateTime>

-

-

tsrange

-

-

PostgisPoint

-

-

geometry

-

-

PostgisLineString

-

-

geometry

-

-

PostgisPolygon

-

-

geometry

-

-

PostgisMultiPoint

-

-

geometry

-

-

PostgisMultiLineString

-

-

geometry

-

-

PostgisMultiPolygon

-

-

geometry

-

-

PostgisGeometry

-

-

geometry

-

-

PostgisGeometryCollection

-

-

geometry

-

-

Dictionary<string, string>

-

-

hstore

-

-

JToken

-

-

jsonb

-

-

JObject

-

-

jsonb

-

-

JArray

-

-

jsonb

-

-

数组

-

-

以上所有类型都支持

-

-

以上类型和长度是默认值,可手工设置,如 string 属性可指定 [Column(DbType = "varchar(max)")]

DbFirst

FreeSql 同样支持 DbFirst 的开发模式,即先有数据库再有项目,这种传统的开发模式永远不会过时,特别适合老项目仍然在维护,或者数据库重构成本过高的项目。关系型数据库有许多成熟的运维和开发类配套工具,例如我们所关注的ER图工具 PowerdeSigner,使用它可以更直观的查看表之间的关系。除了FreeSql作者同时在维护超过十年的代码生成器dotnetGen项目,它是一款支持超快速开发且高度可控的解决方案,非常喜欢 DbFirst 的开发模式,因此在 FreeSql for DbFirst 功能上会有不错的支持。

DbFirst 模式开发主要提供了不同数据库的表结构查询适配,配合模板生成器现实从数据库导入模型到c#代码中。

生成器是基于 DbFirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,实现了三种生成模板:

模板名称

路径

类型映射

外键导航属性

缓存管理

失血

贫血

充血

simple-entity

../Templates/MySql/simple-entity

X

X

X

X

simple-entity-navigation-object

../Templates/MySql/simple-entity-navigation-object

X

X

X

rich-entity-navigation-object

../Templates/MySql/rich-entity-navigation-object

X

X

结语

项目功能与文档较多,许多细节不适合在一篇文章中展示详尽,更多的功能介绍请移步 github wiki 中心。借此文章介绍FreeSql这个国产ORM,希望能得到大家的支持。

FreeSql 口号:打造 .NETCore 最方便的 ORM!

项目地址:https://github.com/2881099/FreeSql

文档中心:https://github.com/2881099/FreeSql/wiki

最后诚心邀请您的参与加入,一起完成 FreeSql 的使命。

以上是 【纯技术贴】.NETStandardFreeSqlv0.0.9功能预览 的全部内容, 来源链接: utcz.com/z/510911.html

回到顶部