对象关系映射器(APF)是一种使得.NET开发者能够使用特定领域的对象来操作关系数据的工具。它消除了开发者通常需要编写的大部分数据访问代码。
APF是一个软件开发框架,它帮助在构建Windows Forms应用程序时构建一个可维护的业务逻辑层。在.NET软件开发环境中存在多种数据访问框架。APF尝试创建一个动态数据库更改的业务逻辑层。与其他框架不同的是,它具有动态灵活的用户界面。
随着业务逻辑的不断变化,这些变化会触发底层数据库的自动更改。这个平台使能够创建一个面向对象的业务层,它抽象并封装了所有的业务逻辑和数据。框架确保随着业务对象的变化,它们仍然能够无缝地工作。任何在业务逻辑层类中发生的更新都会相应地触发底层数据库的更新。
使用该平台的关键好处是它帮助应用几乎可以自构建。
数据访问层(DAL)构建器不需要编写任何代码,它在编译时构建自己,具有完整的对象层和强类型集合。
一个完整的实用工具工具集,包括Rails风格的脚手架、迁移(数据库版本控制)和代码生成器。
一个动态查询工具,让可以使用SQL Server和企业库,而无需了解SQL。
一个OR映射器,扩展到视图和存储过程,所以不会被锁定在OR/M中。
Arkitech平台是一个VB.NET项目,非常松散地基于Subsonic。Subsonic是一个流行的工具集,它显著加快了数据库驱动的Web应用程序的开发时间。Subsonic是由Rob Conery和一个核心开发团队开发的.NET开源项目。此外,还使用了基于Rockford Lhotka的CSLA.NET项目的一般思想。除此之外,可能还有其他一些来自互联网的代码片段。
那么这与Entity Framework (EF)有什么不同呢?EF是一个'代码优先'框架。在这种情况下,不必费心数据库图表,只需编写代表想要存储的对象的POCO类。然后引用这些类在一个特殊的类中,称为DbContext,以使EF将它们持久化到数据库。微软为EF添加了一个关键特性,这个特性只适用于代码优先,那就是迁移。迁移允许更改数据类,然后更新数据库而不丢失数据。
使用APF方法,也有'代码优先'的好处。如果稍后重构代码,那么更改将被迁移到数据存储'即时'。然而,对来说,EF最大的缺点是在DbContext类中。EF中的DbContext类代表一个组合仓库,它可以用于从数据库查询并组合在一起的更改,然后将它们作为一个单元写回到存储中。换句话说,在DbContext类中,所有数据操作都在一个类文件中完成。
DbContext类也可能是一个难以调试的黑匣子;必须追踪它生成的SQL,并弄清楚为什么出了问题。对于那些经常需要回去更改一个特定小项目的人来说,这可能是相当麻烦的。更喜欢业务类的分离,以及它底层的数据操作。在APF中,数据操作是由特定的'管理器'类(例如TaskManager、PeopleManager、UserManager等)完成的。
此外,APF遵循MVC之所以如此流行的趋势。业务关注点的分离意味着视图类分配可以非常具体。不需要将整个DbContext分配给每个视图及其所有机制。通过不分割代码组件,很可能会引入业务关注点之间不希望的耦合。
这个框架通常针对自由职业ISV。一个关键假设是,数据库是新的和/或现有的数据库,有管理权限来修改。另一个假设是,在创建数据库表时使用某种类型的数据库规范化。这里呈现的数据类尽可能接近第四范式(4NF)。
APF使用定制的基于属性的强类型代码映射。这允许在同一个地方保持实体和数据库细节。强类型代码基础允许动态创建数据库模型并对其进行强类型化,因此,例如,如果属性名称更改,映射将不受影响。
APF支持一对一、一对多和多对多。
APF公开了几个查询API:LINQ可能是现在最常用的,实际上不需要介绍;平台API是查询对象模式的实现,通过类模型使用强类型LINQ表达式而不是字符串来创建想要执行的查询的半抽象概念表示;这比使用标准字符串更有利于重构。
APF依赖于三个主要类来实现后端数据库和前端UI之间的通信。对于前端UI,将从Singleton FrameworkConnection类继承。继承的类(例如'Database')在某些方面类似于数据库仓库,类似于DbContext类。每个管理器类引用这个仓库来执行其CRUD操作。
命令类是APF与数据库交互的方式。在这个例子中,InsertCommand类包含一个TableMapping类,它有助于使用元数据分解代码对象,以检索要插入到SQL Server后端的原始数据。
开发者只需要调用管理器类中的方法来执行任何CRUD操作。
Public Overrides Sub Create()
Dim preCount As Integer = Count()
Dim ParentID As Integer = 0
Dim UserID As Integer = 1
Dim StateID As Integer = 1
Dim PriorityID As Integer = 1
Dim CategoryID As Integer = 1
Dim ProjectID As Integer = CreateProject.ProjectID
Dim biz As Task = TaskManager.Default
With biz
.CategoryID = CategoryID
.PriorityID = PriorityID
.ProjectID = ProjectID
.ParentID = ParentID
.StateID = StateID
End With
TaskManager.Insert(biz)
TestObject = biz
CreateChildTask()
TestObject = biz
TestAssert.Equals(Count, preCount + 1)
End Sub