欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

使用数据库元数据为Entity Framwork实体生成注释

程序员文章站 2022-05-01 22:16:03
...

使用数据库元数据为Entity Framwork实体生成注释 众所周知Entity Framwork自动生成的实体上没有注释。 img1 没错,我使用的是Entity Framwork的各种应用模式中的数据库先行模式。本文不讨论Entity Framwork的哪种应用模式更好的问题而是讨论Entity Framwork

使用数据库元数据为Entity Framwork实体生成注释

众所周知Entity Framwork自动生成的实体上没有注释。

img1

使用数据库元数据为Entity Framwork实体生成注释

没错,我使用的是Entity Framwork的各种应用模式中的数据库先行模式。本文不讨论Entity Framwork的哪种应用模式更好的问题而是讨论Entity Framwork提供的T4模板没有生成实体注释的问题。

通常架构数据库的时候会书写描述架构的元数据。如

img2

使用数据库元数据为Entity Framwork实体生成注释

SqlServer把这些元数据存储在哪里我不关心。但是从下图可以发现貌似这种元数据是个键值对结构。并且该类元数据被称作Extended Properties

img3

使用数据库元数据为Entity Framwork实体生成注释

通常数据库会以数据库爱好的方式提供操作数据的接口。操作这里的Extended Properties类别的元数据的接口是什么呢?是下面一个系统元数据函数和三个系统存储过程:

img4

使用数据库元数据为Entity Framwork实体生成注释

img5

使用数据库元数据为Entity Framwork实体生成注释

img6

使用数据库元数据为Entity Framwork实体生成注释

img7

使用数据库元数据为Entity Framwork实体生成注释

这四个接口刚好完成我们所需要的对Extended Properties类别元数据的CRUD操作。可惜,Entity Framwork的实体数据模型中并不包含这类属性。虽然这类元数据与ORM无关但是它们对我们的代码有利,如果能把这类元数据以注释的形式加到实体类代码上的话。

为了确认Entity Framwork的实体数据模型上不包含这类元数据,现在然我们以数据库优先的方式创建一个Entity Framwork项目,随便找一个数据库建好了后从数据库更新元数据

img8

使用数据库元数据为Entity Framwork实体生成注释

在点击“Update Model From Database”之前开启SqlServer Profiler程序

img9

使用数据库元数据为Entity Framwork实体生成注释

通过监视Entity Framwork更新元数据的sql代码可以发现Entity Framwork并没有查询Extended Properties类别的元数据。上面说了这类元数据与ORM这件事情无关,所以干正经事的Entity Framwork根本不需要查询这类元数据。但是我们想要利用数据库中的Extended Properties元数据为实体代码自动添加注释,这件事对于我们来说是正经事。想要利用实体数据模型上的元数据为实体代码添加注释的道路是难以走通了因为Ef都根本没去查这类元数据。

那么,我们自建模型。通过监视Entity Framwrok从数据库更新元数据的Sql代码我们领会到了SqlServer元数据数据访问方面的知识。研究发现为生成实体数据模型元数据Entity Framwork查询下如下结构的四种数据:

img10

使用数据库元数据为Entity Framwork实体生成注释

上图四种元数据分别对应SqlServer的表、视图、表列和视图列。当然这四类元数据现在表现为四张数据库视图这是经过我封装好了的。我们将这四张视图作为提供元数据的“接口”。没错就是“接口”,谁规定过接口必须是C#中的interface关键字定义的结构?接口是契约,这四张视图就是我们的数据库契约,现在我建的每个数据库都实现了这个接口,它们都具有这四张视图。这四张视图是通过参考Entity Framwork获取元数据的Sql语句建立的。这些Sql查询太过复杂,尤其查询表列和视图列的元数据的查询语句复杂的让人难以入眼,下面只贴一个表视图吧:

img11

使用数据库元数据为Entity Framwork实体生成注释

有了上面四张视图,再加上三个系统存储过程sys.sp_addextendedproperty、sys.sp_updateextendedproperty、sys.sp_dropextendedproperty和一个系统元数据函数::fn_Listentendedproperty,如果这些知识都是我们熟悉的或者留意过的则大部分人可以在头脑中有一个大致的解决方案了。但作为善终,本文还得继续。废话少说,下面开始架构和编码。

讨论到现在发现一直都是在围绕着数据库说事,可见数据库这个概念很重要,所以我想把它抽象一下先,建个Db类:

img12

使用数据库元数据为Entity Framwork实体生成注释

Db类很简单基本没有什么可说的,唯有它的GetConnection方法值得一说,我们将上面的类图换个视角看一看:

img13

使用数据库元数据为Entity Framwork实体生成注释

Db类的GetConnection方法构建数据库连接的任务是通过委托ADO.NET的DbProviderFactory类型的对象完成的,而dbProviderFactory作为DbProviderFactory类型的实例是通过ADO.NET的DbProviderFactories.GetFactory(this.ProviderName)静态方法传入ProviderName字符串构建的

img14

使用数据库元数据为Entity Framwork实体生成注释

当然除了Db类外,我们也需要为表、表列、视图、视图列类别的元数据建模,不过它们四个并没有出彩的地方:

img15

使用数据库元数据为Entity Framwork实体生成注释

还记得前文提到的数据库上的那四个视图接口么?上图的这四个对象模型映射的就是数据库中的那四个视图(关系模型)。Db类型的对象不需要持久化吗?当然需要,它持久化到数据库中的Database表:

img16

使用数据库元数据为Entity Framwork实体生成注释

同样Database表也没有什么出彩的地方,前文有一张图上提到数据库连接“引导库”,香港服务器,Database表所在的库就是这个引导库。

模型建好的,为了简化问题,就把上面的Db模型、DbTable模型、DbView模型、DbTableColumn模型和DbViewColumn模型当数据访问模型。现在基于这四个模型定义一套元数据访问接口:

img17

使用数据库元数据为Entity Framwork实体生成注释

目前来说有意义的是图上红色矩形圈住的几个方法。这几个方法就是用以实现对Extended Properties类别的数据库元数据的增删改操作的,它们都是通过调用一个很臭的私有方法实现的:

img18

使用数据库元数据为Entity Framwork实体生成注释