FreeSql 新的八大骚功能,.NETCore 你必须晓得的 ORM

前言

FreeSql 目前版本号 0.5.5,预计明年元旦发布 1.0.0,切莫小看了版本号,目前单元测试方法1350+,并且每个方法内的涵盖面又比较广(不信的话见下图),每一次版本发布都作了较多的测试工作。

最近的一段时间,关注我们的人时不时会看见扩展包发布,今天振奋人心的功能主要是核心部分实现(扩展包今天当配角)。就不多啰嗦了,咱们直接入主题。

功能一:MapType 类型映射

使用 codefirst 时序列化 json 或 jsonb 数据类型报错

使用 postgresql + ef 配置数据映射关系,使用 FreeSql 的映射扩展时,对于json类型的数据映射出错。

这是来自 github 上的某个 issue,原因是用户的实体定义了 string,数据库类型为 json。FreeSql 本身支持了丰富的类型,不限于 json,但是限定了类型的映射,比如 JToken/JObject/JArray 的实体类型才可以映射至 PostgreSQL 数据库的 json 类型。另外虽然有 DbType 特性可以设置,但使用范围有限,不可跨越类型(如使用 string 可使用 DbType="char(100)")。

还有类似的,如:将 enum 映射到数据库 varchar 的请求。。。。

到现在,我们已经彻底突破了这个障碍,基本可以做到随意映射类型。作为新项目开发,我们提供本身的默认类型映射已经非常人性化,提这些需求的人主要还是历史原因,咱们做程序维护工作的人员还是占比很高,千怪万怪只能怪 FreeSql 来得太迟。。。。

目前为 MapType 功能增加了大约 400 个单元测试方法。贴一段 demo 配置方法:

class EnumTestMap {
    public Guid id { get; set; }

    [Column(MapType = typeof(string))]
    public ToStringMapEnum enum_to_string { get; set; }
    [Column(MapType = typeof(string))]
    public ToStringMapEnum? enumnullable_to_string { get; set; }

    [Column(MapType = typeof(int))]
    public ToStringMapEnum enum_to_int { get; set; }
    [Column(MapType = typeof(int?))]
    public ToStringMapEnum? enumnullable_to_int { get; set; }

    [Column(MapType = typeof(string))]
    public BigInteger biginteger_to_string { get; set; }
    [Column(MapType = typeof(string))]
    public BigInteger? bigintegernullable_to_string { get; set; }
}
public enum ToStringMapEnum { 中国人, abc, 香港 }

应该不需要解释了吧?

细看一下,实体内有 BigInteger 类型,这可是数据库无法表示的类型,现在就是可以使用(没辙)。但请注意:BigInteger 仅仅是 CURD 方便, Equals == 判断可以使用,无法使用 + - * / < > 等操作;

默认映射

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
NpgsqlPoint?
- - point - -
NpgsqlLine
NpgsqlLine?
- - line - -
NpgsqlLSeg
NpgsqlLSeg?
- - lseg - -
NpgsqlBox
NpgsqlBox?
- - box - -
NpgsqlPath
NpgsqlPath?
- - path - -
NpgsqlPolygon
NpgsqlPolygon?
- - polygon - -
NpgsqlCircle
NpgsqlCircle?
- - circle - -
(IPAddress, int)
(IPAddress, int)?
- - cidr - -
IPAddress - - inet - -
PhysicalAddress - - macaddr - -
NpgsqlRange<int>
NpgsqlRange<int>?
- - int4range - -
NpgsqlRange<long>
NpgsqlRange<long>?
- - int8range - -
NpgsqlRange<decimal>
NpgsqlRange<decimal>?
- - numrange - -
NpgsqlRange<DateTime>
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)")]

功能二:唯一键(Unique)

class AddUniquesInfo {

    public Guid id { get; set; }
    [Column(Unique = "uk_phone")]
    public string phone { get; set; }

    [Column(Unique = "uk_group_index")]
    public string group { get; set; }
    [Column(Unique = "uk_group_index")]
    public int index { get; set; }

    [Column(Unique = "uk_group_index222")]
    public string index22 { get; set; }
}

Unique 指定相同的标识,代表联合唯一键,现已支持迁移。

功能三:弱类型(实体)

之前在操作实体时,必须传统泛型参数,现在可以实现弱类型实体的操作。以 Repository 为例:

var repos = fsql.GetGuidRepository<object>();
repos.AsType(typeof(AddUpdateInfo));

var item = new AddUpdateInfo();
repos.Insert(item);

item.Clicks += 1;
repos.InsertOrUpdate(item);

var item2 = repos.Find(item.Id) as AddUpdateInfo;
Assert.Equal(item.Clicks, item2.Clicks);

repos.DataFilter.Apply("xxx", a => (a as AddUpdateInfo).Clicks == 11);
Assert.Null(repos.Find(item.Id));

然后呢,DbContext 也支持同样的操作。

dotnet add package FreeSql.DbContext

功能四:ToList & Mapper

现在支持 ToList(a => new Dto()) 这样的简单数据映射。

什么意思?即 Dto 只要有属性名与实体属性相同,就会根据匹配到的字段查询(不是查询所有字段回来再映射)。

然后这个骚操作,还支持多表查询的映射,怎么解决多表存在相同名字的字段问题呢?优先级规则,它会依次序匹配 LeftJoin/InnerJoin/RightJoin 的实体。

功能五:ToList 贪婪加载

以前 .ToList() 会加载两级Join对象;

现在 ISelect.ToList(includeNestedMembers: true) 贪婪加载所有 LeftJoin/InnerJoin/RightJoin 导航数据,不论对象的层级;

功能六:WhereDynamic 动态条件

支持传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}。

也就是说 WhereDynaimc 方法输入类型为 object,是不是很方便?还支持联合主键呢。

功能七:IAdo.Query 多个结果集

var result = fsql.Ado.Query<T1, T2>("select * from t1; select * from t2");

功能八:开发环境之利器:MVC 中间件 FreeSql.AdminLTE

大约是前一段时间的某一天(废话),因为使用 FreeSql 的某项目需要做一个简单的后台功能,以便录入或管理数据。在实施的过程中好怀念当初 dotnetGen 生成器的味道,用它产生 curd 基本功能几乎是秒做;

FreeSql.AdminLTE,是的就是它,前段时间发布过一次。

它是 FreeSql 衍生出来的 .NETCore MVC 中间件、中间件、中间件(重复三遍)扩展包,基于 AdminLTE 前端框架动态产生实体的增删查改界面;

输入:实体1、实体2、实体3

输出:后台管理的功能

只需要传入实体,就可以形成 curd 的管理功能,是不是有些骚啊~~~

先发一张运行后的图片尝个鲜:

这是根据实体产生 curd 界面的 mvc 中间件,开发时预览数据好方便啊。看完预览图不由得再感叹一次 FreeSql 的易用性,那句口号:做 .NETCore 最方便的 ORM! 没有说错。。。作者多次提及:“我们是日式简约风格,没那么复杂的用法”,也验证了这一点。。

添加/修改

中件间产生的界面包括添加、修改数据的功能,普通实体的根据属性的类型与 Html5 UI 一一映射;

比较特殊的映射规则:

c# 类型 Html5
布尔 复选框
枚举 下拉选择
日期 日期控件
ManyToOne 导航属性 下拉选择
ManyToMany 导航属性 多选器

等等。。。

什么情况会产生【上传文件】控件?
有兴趣的可以了解源码,目前没有开放在外部配置。

查询/过滤

中件间为每个实体提供了分页列表查询,每页为20条数据;

除此外,还提供了过滤条件的支持,规则是根据导航属性(ManyToOne、ManyToMany)。比如【文章实体】,内含有【分类id】+【分类对象】,则【文章】列表页会出现按【分类】筛选的UI,详见上面的 demo 示意图,或者下载对应的 demo 版本运行;

删除

中件间为每个实体提供了批量删除的功能;

测试 demo

我们习惯用 sqlite 做测试库,测试完毕直接删除目录,不留垃圾数据,所以下面的 demo 不需要修改任何地方,运行时自动建库、建表;

提供 .net core 2.1、2.2 两种环境的测试 demo 下载:

Demo for dotnet 2.1.zipDemo for dotnet 2.2.zip

image

第一步:

dotnet restore

第二步:

dotnet run

思考

一番惊喜过后,你应该会考虑实用性,这样做有什么价值,可用于什么样的场景?

这个扩展包简单的输入,产生巨量的功能反馈。目前来说它是死板的,对外提供的扩展性几乎为零,这样也就限定了它的应用场景。

不合适的场景

1、它不可替代我们自身开发的后台管理系统;

2、它不适合摆放在公网正式环境,存在数据安全问题;

3、欢迎补充。。。;

谈谈定位

目前的定位是这样的,在开发环境中使用,查阅预览实体数据,同时也比较方便的管理测试数据。

一段拥有无比力量的小段代码,也是中间件界面的功能开启:

//可以配置子目录访问,如:/testadmin/
app.UseFreeAdminLTE("/",
    typeof(Entities.Song),
    typeof(Entities.Tag));

观后抽奖

我们一直在发布纯技术干货的分享文章,FreeSql 已经基本完成 .NETCore 最方便的 ORM 使命,我们正在筹备生态的建立,比如 ABP 中如何使用 FreeSql 的实现,需要各种各样的扩展包,好多好多工作量。有没有大神愿意无偿参与做这件事情,好吧。。应该没有人!!如果你回心转意了,欢迎联系我们。

欢迎持续关注我们,做 .NETCore 最方便的 ORM !

QQ群:4336577(已满)、8578575(在线)、52508226(在线)

github: https://github.com/2881099/FreeSql

说好的抽奖呢???

posted @ 2019-04-27 02:45  nicye  阅读(7960)  评论(22编辑  收藏  举报