很高兴我们的 ORM 数据访问框架(Zongsoft.Data)在历经两个 SaaS 产品的应用之后,今天正式宣布对外推广。

它是一个类 GraphQL 风格的 ORM(Object/Relational Mapping) 数据访问框架。

又一个轮子?

在很长时间里,.NET 阵营似乎一直缺乏一个被普遍使用的 ORM 数据访问框架,从最早的原生 ADO.NET 到舶来品 iBatis.NETHibernate.NET,后来又经历了 Linq for SQL 与 Entity Framework 的混战,可能是因为 Entity Framework 早期版本的模糊定位和反复变更的设计导致了它失之霸主之位,进而造就了一段百舸争流、群雄共逐的战国时代。在历经漫长而反复的期待、失望、纠结和痛苦之后,我终于决定动手造一个轮子。

设计理念

在开始动手之前,先确定以下基本设计原则:

  • 数据库优先(Database First)

  • 严格的 POCO/POJO 支持

  • 映射模型与代码完全隔离

  • 禁止业务层出现 SQL 和类 SQL 代码

在一个业务系统中,数据结构及其关系毋庸置疑是最底层的基础性结构,数据库应由系统架构师或开发负责人进行仔细设计No Schema/Weakly Schema 的思潮是涂抹了蜂蜜的毒药),数据访问映射以数据库表结构关系为基石,在此之上业务层亦以概念映射模型为准绳,层级之间相互隔离。

领域模型实体避免通过注解(标签)来进行元数据定义,应确保严格符合 POCO/POJO 范式。通过语义化的 Schema 来声明访问的数据结构关系,禁止应用层的 SQLLinq 式的类 SQL 代码可降低业务层对数据层的依赖、提升代码可维护性外,还具备更加统一可控的便利性,并为数据访问引擎的实现提供了更大的优化空间和自由度。

范例说明

下面通过三个的例子(注:例子均基于 Zongsoft.Community 项目)来佐证上面的部分设计理念,更多示例和阐述请参考 Zongsoft.Data 项目的 README.md 文档和 Zongsoft.Community 项目的代码。

提示:下面的范例均基于 Zongsoft.Community 开源项目,该项目是一个完整的论坛社区的后台程序。你可能需要预先阅读一下该项目的《数据库表结构设计》文档,以便更好的理解范例代码的业务逻辑。

示例一

导航查询及导航过滤

var forums = this.DataAccess.Select<Forum>(    Condition.Equal("SiteId", this.User.SiteId) &    Condition.In("Visibility", Visibility.Internal, Visibility.Public) |    (        Condition.Equal("Visibility", Visibility.Specified) &        Condition.Exists("Users",                  Condition.Equal("UserId", this.User.UserId) &                  (                      Condition.Equal("IsModerator", true) |                      Condition.NotEqual("Permission", Permission.None)                  )        )    ),    "*, MostRecentThread{ThreadId,Title,Creator{Name,Nickname,Avatar}}"

);

上述数据访问的查询方法大致生成如下SQL脚本:

SELECT    t.*,    t1.ThreadId AS 'MostRecentThread.ThreadId',    t1.Title AS 'MostRecentThread.Title',    t1.CreatorId AS 'MostRecentThread.CreatorId',    t2.UserId AS 'MostRecentThread.Creator.UserId',    t2.Name AS 'MostRecentThread.Creator.Name',    t2.Nickname AS 'MostRecentThread.Creator.Nickname',    t2.Avatar AS 'MostRecentThread.Creator.Avatar'FROM Forum t    LEFT JOIN Thread AS t1 ON        t.MostRecentThreadId=t1.ThreadId    LEFT JOIN UserProfile AS t2 ON        t1.CreatorId=t2.UserIdWHERE    t.SiteId = @p1 AND    t.Visibility IN (@p2, @p3) OR    (        t.Visibility = @p4 AND        EXISTS        (            SELECT u.SiteId, u.ForumId, u.UserId            FROM ForumUser u            WHERE u.SiteId = t.SiteId AND                  u.ForumId = t.ForumId AND                  u.UserId = @p5 AND                  (                      u.IsModerator = @p6 OR                      u.Permission != @p7                  )        )    );

上述示例通过 Select 查询方法的 schema 参数(即值为 *, MostRecentThread{ThreadId,Title,Creator{Name,Nickname,Avatar}} 的参数)从数据结构关系的层次指定了查询数据的形状,因而不再需要 SQL 或类 SQL 语法中 JOIN 这样命令式的语法元素,它不光提供了更简洁且语义化的 API 访问方式,而且还给数据访问引擎底层提供了更大的优化空间和自由度。

如果将 Select 查询方法的 schema 参数值改为 *,Moderators{*},MostRecentThread{ThreadId,Title,Creator{Name,Nickname,Avatar}} 后,数据访问引擎会将查询内部分解为一对多的两条 SQL 语句进行迭代执行,而这些都不需要业务层进行分拆处理,因而提升了效率并降低了业务层的复杂度。

Schema 模式表达式通过 Web API 提供给前端应用,将大大减少后端开发的工作量,提升前后端的工作效率。

示例二

一对多的关联新增

// 构建待新增的实体对象var forum = new{    SiteId = this.User.SiteId,    GroupId = 100,

    Name = "xxxx",

    // 一对多的导航属性    Users = new ForumUser[]    {        new ForumUser { UserId = 1001, IsModerator = true },        new ForumUser { UserId = 1002, Permission = Permission.Read },        new ForumUser { UserId = 1003, Permission = Permission.Write },    }

}

// 执行数据新增操作

this.DataAccess.Insert<Forum>(forum, "*, Users{*}");

上述数据访问的新增方法大致生成如下SQL脚本:

/* 主表插入语句,执行一次 */INSERT INTO Forum (SiteId,ForumId,GroupId,Name,...) VALUES (@p1,@p2,@p3,@p4,...);/* 子表插入语句,执行多次 */INSERT INTO ForumUser (SiteId,ForumId,UserId,Permission,IsModerator) VALUES (@p1,@p2,@p3,@p4,@p5);

上述示例通过 Insert 新增方法的 schema 参数(即值为 *,User{*} 的参数)指定了新增数据的形状,由数据访问引擎根据映射定义自动处理底层的 SQL 执行方式,确保业务层代码的简洁和更高的执行效率。

示例三

一对一和一对多的关联更新,对于“一对多”的导航属性,还能确保该属性值 (集合类型) 以 UPSERT 模式写入。

public bool Approve(ulong threadId){    //构建更新的条件    var criteria =        Condition.Equal(nameof(Thread.ThreadId), threadId) &        Condition.Equal(nameof(Thread.Approved), false) &        Condition.Equal(nameof(Thread.SiteId), this.User.SiteId) &        Condition.Exists("Forum.Users",            Condition.Equal(nameof(Forum.ForumUser.UserId), this.User.UserId) &

            Condition.Equal(nameof(Forum.ForumUser.IsModerator), true));

    //执行数据更新操作    return this.DataAccess.Update<Thread>(new    {        Approved = true,        ApprovedTime = DateTime.Now,        Post = new        {            Approved = true,        }    }, criteria, "*,Post{Approved}") > 0;

}

上述数据访问的更新方法大致生成如下SQL脚本:

/* 以下代码为支持 OUTPUT/RETURNING 子句的数据库(SQLServer,Oracle,PostgreSQL) *//* 根据更新的关联键创建临时表 */CREATE TABLE #TMP(    PostId bigint NOT NULL

);

/* 更新主表,并将更新的关联键输出到内存临时表 */UPDATE T SET    T.[Approved]=@p1,    T.[ApprovedTime]=@p2OUTPUT DELETED.PostId INTO #TMPFROM [Community_Thread] AS T    LEFT JOIN [Community_Forum] AS T1 ON /* Forum */        T1.[SiteId]=T.[SiteId] AND        T1.[ForumId]=T.[ForumId]WHERE    T.[ThreadId]=@p3 AND    T.[Approved]=@p4 AND    T.[SiteId]=@p5 AND EXISTS (        SELECT [SiteId],[ForumId]        FROM [Community_ForumUser]        WHERE [SiteId]=T1.[SiteId] AND              [ForumId]=T1.[ForumId] AND              [UserId]=@p6 AND              [IsModerator]=@p7

    );

/* 更新关联表 */UPDATE T SET    T.[Approved]=@p1FROM [Community_Post] AS TWHERE EXISTS (    SELECT [PostId]    FROM #TMP    WHERE [PostId]=T.[PostId]);

上述示例通过 Update 更新方法的 schema 参数(即值为 *,Post{Approved} 的参数)指定了更新数据的形状,数据访问引擎将根据数据库类型生成高效的 SQL 语句,对于业务层而言这一切都是无感的、透明的。

对于一对多的导航属性,数据访问引擎默认将以 UPSERT 模式处理子集的写入,关于 UPSERT 更多信息请参考 Zongsoft.Data 项目文档。

性能

我们希望提供最佳的综合性价比,对于一个 ORM 数据访问引擎来说,性能的关注点主要(不限)有这些要素:

  1. 生成简洁高效的 SQL 脚本,并尽可能利用特定数据库的最新 SQL 语法;

  2. 数据查询结果的实体组装(Populate)过程必须高效;

  3. 避免反射,有效的语法树缓存。

实现层面我们采用 Emitting 动态编译技术对实体组装(Populate)、数据参数绑定等进行预热处理,可查阅 DataPopulator 等相关类的源码深入了解。

其他

得益于 “以声明方式来表达数据结构关系” 的语义化设计理念,相对于命令式设计而言,它使得程序意图更加聚焦,天然地对底层数据的表达和优化更加宽容与自由。

更多详细内容(譬如:读写分离、继承表、数据模式、映射文件、过滤器、验证器、类型转换、数据隔离)请查阅相关文档。

支持赞助

我们欢迎并期待任何形式的推广支持!

如果你认同我们的设计理念请为这个项目点赞(Star),如果你认为该项目很有用,并且希望支持它未来的发展,请给予必要的资金来支持它:

  1. 关注 Zongsoft 微信公众号,对我们的文章进行打赏;

  2. 加入 Zongsoft 知识星球圈,可以获得在线问答和技术支持;

  3. 如果您的企业需要现场技术支持与辅导,又或者需要开发新功能、即刻的错误修复等请发邮件给我。


提醒:点击左下角的“阅读原文”会有更好的阅读体验。

Zongsoft.Data 发布公告相关推荐

  1. SAIF MBA2011年学费与资助政策发布公告

    SAIF MBA2011年学费与资助政策发布公告 亲爱的申请人: SAIF MBA2011年学费与资助政策现已通过学院网站发布.谨此公告. 我院采用国际化办学模式,强调专业视角,MBA课程以" ...

  2. 微博发布公告 将开展财经违规内容专项整治行动

    8月28日消息,微博对外发布公告称,为贯彻落实国家网信办"清朗"系列专项行动要求,进一步规范网络传播秩序,即日起,微博将开展财经违规内容专项整治行动. 微博将重点打击以下8类违规问 ...

  3. 恒大汽车发布公告 拟在科创板上市

    9月26日消息,昨日晚间,恒大汽车发布公告,董事会已于2020年9月25日审议通过建议根据特别授权发行人民币股份及相关事宜的决议案. 公告显示,根据建议发行人民币股份的方案,本公司拟申请首次公开发行人 ...

  4. storm和vgj vgj_Team VGJ发布公告解散 两年征程划上句号

    鉴于V社新规,在前阵子北美战队VGJ.Storm发布公告,宣布与VG俱乐部的合作已经到期,将会脱离VG成立一家新的电竞俱乐部,并且更名为J.Storm.此后,国内战队VGJ.T在今天中午发布公告,宣布 ...

  5. 物联网操作系统HelloX V1.83发布公告

    物联网操作系统HelloX V1.83发布公告 经过HelloX开发团队近半年的努力,在HelloX V1.82版本基础上,增加许多功能特性,并对V1.82版本的一些特性进行了进一步优化之后,正式形成 ...

  6. 物联网操作系统HelloX V1.82发布公告

    物联网操作系统HelloX V1.82发布公告 经过HelloX开发团队近半年的努力,在HelloX V1.81版本基础上,增加许多功能特性,并对V1.81版本的一些特性进行了进一步优化之后,正式形成 ...

  7. OpenJWeb(v1.9)企业级信息化应用平台开源版发布公告(基于Java语言开发)

              OpenJWeb(v1.9) 企业级信息化应用平台 开源版发布公告 (基于Java语言开发)     软件开发人员的创业伴侣.架构参考 软件外包公司的二次开发利器 Java培训机构 ...

  8. Spring Data 发布更改版本管理方案之后的第一个版本:2020.0.0

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 2020年10月28日 Spring Data自更改版本 ...

  9. 海底捞发布公告 预计去年最高亏损45亿

    2月21日消息,海底捞对外发布公告称,2021年收入预计超过400亿元,同比增长超过40%.预计净亏损为38-45亿元,相比较下,2020年净利润约为3亿元. 在公告中,对于亏损的原因,海底捞表示,2 ...

最新文章

  1. three.ar.js_我们如何通过AR.js使产品吉祥物栩栩如生
  2. stat_count() must not be used with a y aesthetic
  3. try not do unnecessary subscriptions
  4. c 命令导出数据到mysql_MySQL命令行导出数据库
  5. OllyDBG反汇编快速找到程序入口一点分析
  6. 使用Rss框架PHP开发流程
  7. 【C#复习总结】细说表达式树
  8. matlab在循环中保存jpg格式_Matlab如何循环读取文件
  9. tomcat上的javaweb项目如何将ip地址更换为域名_Java Web 路线规划
  10. 选择数据分析软件时要注意什么
  11. 配置Apache2+PHP5+MYSQL5
  12. 李宏毅机器学习Regression
  13. python给ppt表格加边框_向ppt里插入图片和表格
  14. 为什么计算机能读懂 1 和 0
  15. 全球高效能人士给青年的50个忠告(上)
  16. json发送数据加密方法_发送加密的电子邮件和安全邮件的最佳免费方法
  17. 深入理解Flash Player的安全域
  18. godaddy 服务器位置,GoDaddy DNS服务器地址 | Godaddy美国主机中文指南
  19. NLP自然语言处理CRF详解
  20. python画条状图_Python 绘制分组条形图

热门文章

  1. 自定义控件复选框和单选框的实现
  2. [译] 机器学习可以建模简单的数学函数吗?
  3. Python基础教程:Python pass语句详解
  4. Educational Codeforces Round 37 (Rated for Div. 2) 1
  5. 网站常见漏洞-- XSS攻击
  6. lambda与内置函数
  7. Android简单封装类似JQuery异步请求
  8. error LNK2001: unresolved external symbol public: __thiscall CNaDialog::CNaDialog(class CWnd *)
  9. Linux和Windows下部署BeetleX服务网关
  10. .NET再出发!20岁生日快乐