<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>C# on Ayakura Yuki 的小窝</title><link>https://blog.ayakurayuki.cc/tags/c%23/</link><description>Recent content in C# on Ayakura Yuki 的小窝</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sat, 03 Jun 2017 13:00:00 +0000</lastBuildDate><atom:link href="https://blog.ayakurayuki.cc/tags/c%23/index.xml" rel="self" type="application/rss+xml"/><item><title>CodErator开发笔记</title><link>https://blog.ayakurayuki.cc/p/2017-06-03-coderator-develop-note/</link><pubDate>Sat, 03 Jun 2017 13:00:00 +0000</pubDate><guid>https://blog.ayakurayuki.cc/p/2017-06-03-coderator-develop-note/</guid><description>&lt;blockquote&gt;
&lt;p&gt;CodErator 取自 Code Generator，这么一结合，既有代码生成器的含义，又有代码操作者的意味，亦或是更多的含义。既然定位在轻量级代码生成工具，只要能完成任务，就是最好的了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="关于项目的启发"&gt;关于项目的启发
&lt;/h2&gt;&lt;p&gt;这个项目在建立之前，我有一段时间用过 CodeSmith 试用版，也写了两个使用 CodeSmith 生成 JavaEE 主流框架代码的模板（参见&lt;a class="link" href="https://github.com/AyakuraYuki/SSMGenerator" target="_blank" rel="noopener"
&gt;SSMGenerator&lt;/a&gt;，另一个尚未发布）。但众所周知，CodeSmith 可不是个亲近的家伙，收费，且新版（ver.7.1）不能使用 Visual Studio 编写模板（它自建了一个 Template Editor），所以 CodeSmith 使用成本就这么摆在这里了。&lt;/p&gt;
&lt;p&gt;既然我想完成一个简单的代码生成工作，又不想专门为你出这个钱，而且你又把部分 DLL 的代码公布了，那我不如自己写一个轻便的生成工具，只要能完成工作就好了呗。就是这样的想法，促成了这个项目的产生。&lt;/p&gt;
&lt;h2 id="开发设计"&gt;开发设计
&lt;/h2&gt;&lt;p&gt;老实说，这个项目因为还有另一个目的，就是课程设计，花在这个项目初始版本上的时间就显得比较紧，所以并没有什么设计。&lt;/p&gt;
&lt;p&gt;稍微对我过去开发的情况做了个估计，这个项目姑且算是利用 Build and Fix Model 完成开发，仅有一个思想驱使项目进程的发展：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我需要读到元数据，然后利用元数据封装成对象，通过模板引擎传送到模板文件最后生成目标代码。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="然而"&gt;然而。。。
&lt;/h3&gt;&lt;p&gt;最后却转变成了，通过对生成代码的操作流程去编写功能，而在此基础上对每一个流程可能会出现的误操作做出相应的限制动作，使得流程变得线性化，间接体现出易用性。&lt;/p&gt;
&lt;h3 id="所以"&gt;所以！
&lt;/h3&gt;&lt;p&gt;通过对流程的分析，可以知道使用者需要做的事情能够拆分成如下的动作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;连接到数据库，获取库下的 table 列表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用者可以点击单个 table 列表项查看该表将要被生成的字段内容，此举是为了解决 CodeSmith 的某些“缺陷”，即你能看到 schemas 和 tables，但你看不到 columns&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用者在 table 列表中选择想要生成的一或多张表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用者选择生成目标代码的语言和想要生成的层面&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;选择输出位置，开始生成&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="设计中出现的需求"&gt;设计中出现的需求
&lt;/h2&gt;&lt;p&gt;既然提取出了“生成代码”用例的概要动作，那么就要对这些动作需要哪些技术、功能等进行分析：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;连接到任意的数据库，收集连接数据（但不允许持久化这些连接数据）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;获取 tables 和相应 table 的 columns&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;收集生成选项&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;封装查找到的 Table 和 Columns&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用模板文件去生成代码而不是硬编码到源代码中去生成&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="对于上述设计和需求我采用了以下支持"&gt;对于上述设计和需求，我采用了以下支持
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;既然是连接到数据库，那么我就加入 MySQL 和 SQL Server 的支持吧，反正使用 Oracle 的程序猿不一定会用轻量级代码生成器的吧&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;模板，就你了，Razor Engine&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;界面？WinForm 咯，今后再移植 WPF 吧&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;其他的？那还真没有什么技术可言了，就只是普通 C#而已&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单独拿模板出来说一下事。我在考虑模板使用的时候，考虑过以下四种模板：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;CodeSmith 的 cst&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;T4 文本模板（Text Template Transformation Toolkit）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;NVelocity（Velocity 的.Net 版）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Razor Engine&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;cst 自然不用说，结合 CodeSmith 的 SchemaExplorer，可以省略复杂的客户端操作，直接在模板内声明几个参数然后在客户端给参数赋值，就可以完成生成。问题来了，CodeSmith 本身是收费软件，调用他们的 DLL 很容易，可是会给你跳出个他们家的产品注册窗口，这就很哭笑不得了。&lt;/p&gt;
&lt;p&gt;T4 文本模板，是微软自家的代码生成文本模板，原本在我看来是个比较好的模板，而且写起来跟写 cst 没什么差别，但问题是，T4 文本模板本身就是一个可运行的“class”，这就显得代码不可控了，用户侧可能就会出现各种各样的问题。&lt;/p&gt;
&lt;p&gt;NVelocity，其实就是 Velocity，只不过有人把它.Net 化了。不过这个扩展据我查找的资料，大多文章的发布年是在 2011 年和 2013 年，而该项目本身停留在了 0.4.2 版，发布日期还是 2003 年 10 月。想想现在 Velocity 都什么版本了，天差地别了吧。&lt;/p&gt;
&lt;p&gt;Razor Engine，直到 2016 年还在维护的.Net 模板引擎。它的工作方式更像我所熟知的 Java Controller 传递对象到 jsp 等模板的方式，而且它是非侵入式的模板引擎，想用即可，几乎不需要任何配置，而且测试方便。&lt;/p&gt;
&lt;p&gt;Razor Engine 的基本工作方式可以描述为如下的流程。首先，程序从文本读取到 cshtml 模板文件的内容，将这些内容保存到 string 类型的变量中，然后只需要通过：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-groovy" data-lang="groovy"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Razor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RunCompile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unique_name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;modelType&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这个方法，让引擎获取模板内容和 model 数据，自动替换模板内容内占位符对应的 model 信息，最后返回结果字符串。&lt;/p&gt;
&lt;h2 id="程序使用过程中可能会出现的搞事操作与处理办法"&gt;程序使用过程中可能会出现的搞事操作与处理办法
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;没有连接数据库就执行生成：检测到连接数据不完善，立即终止操作并弹出提示。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有选择表：很少会出现的错误吧，真的出现的话就终止操作并提醒一下。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有选择语言就选择层面，或者反过来没有选择层面只选择语言：一样终止操作，并提示缺少了什么没有选。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有选择输出目录：终止操作，弹出消息框提醒。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据库连接异常：故意输入错误的连接信息对吧？吃我个连接时异常信息提醒！（当然是友好的消息框啦）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;模板文件异常：很遗憾的是，我没办法检测你的模板到底出了什么错，至少现在是没办法的，只能给你丢一个友善的提醒了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="对于数据的处理"&gt;对于数据的处理
&lt;/h2&gt;&lt;p&gt;上面提到了“获取 tables 和相应 table 的 columns”，加之 Razor 需要提供一个 model 来传递参数（当然，RunCompile 还能接受更多对象），那么肯定会想到封装了。然而我稍微了解了一下 System.Data 下的类，事情好像并不是那么容易，比如我需要一个 DataTable 去读取一个 table 下的字段元数据，但我却拿不到表名（不能更方便地拿到表名，需要写一长串调用关系，而事实上是可以的）。&lt;/p&gt;
&lt;p&gt;于是，为了使封装后的数据调用起来更懒人化，我创建了两个 Model：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Table&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Column&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这就显得比较“粗暴”了，获取了表名交给 Table，获取了这个表的所有字段元数据，分别封装成 Column 交给 Table 里的 list。&lt;/p&gt;
&lt;p&gt;这样一来，最后在模板内的调用就可以直接用属性去拿到信息了。&lt;/p&gt;</description></item><item><title>CodErator</title><link>https://blog.ayakurayuki.cc/p/2017-06-03-coderator/</link><pubDate>Sat, 03 Jun 2017 12:00:00 +0000</pubDate><guid>https://blog.ayakurayuki.cc/p/2017-06-03-coderator/</guid><description>&lt;h1 id="coderator"&gt;&lt;a class="link" href="https://github.com/AyakuraYuki/CodErator" target="_blank" rel="noopener"
&gt;CodErator&lt;/a&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;轻量级代码生成工具&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;查询元数据，暴力封装元数据信息，暴力生成源码，能生成就是好工具，反正都要按需求改！&lt;/p&gt;
&lt;h2 id="环境与依赖"&gt;环境与依赖
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;项目创建于 Visual Studio 2017&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;.Net Framework 4.5.2&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;WinForm&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;“难用”的要死的&lt;a class="link" href="https://github.com/Antaris/RazorEngine" target="_blank" rel="noopener"
&gt;Razor Engine 3.9.3&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MySQL Connector.Net 6.9&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="使用目标"&gt;使用目标
&lt;/h2&gt;&lt;h3 id="javaee"&gt;JavaEE
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SSM 框架代码生成&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可自由选择需要生成的层面&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="csharp"&gt;CSharp
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;生成 Entity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="支持功能"&gt;支持功能
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;连接到指定 schema，尚未支持不指定 schema 的连接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;表字段内容获取&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;列表多选即可选择需要生成的表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;指定输出位置&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="开发路线"&gt;开发路线
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;项目初始版本属于 XP 模型产物，根据开发过程遇到的问题，可能需要在代码框架、逻辑设计上重新进行分析。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;初始版本对模板的支持比较严格，不建议用户修改模板文件。然而这不是废话吗？并不，我鼓励各位根据自己的需求或者代码风格去修改模板文件，只要遵守现有的文件名以及 Razor Engine 语法即可。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;未来考虑对模板支持进行大的修改，做到支持程序猿自己定义的模板。这个修改只要确保程序猿们遵守了 Razor Engine 语法，就可以生成代码，不受模板文件名的影响。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;上述开发路线说明或许会因为懒癌发作延期，作为开源项目，如果各位愿意的话，倒不是不可以去修改。欢迎 fork，不求 star。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="现存问题"&gt;现存问题
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;模板文件是定死的，包括文件名（前缀后缀）、文件数量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;仅支持三层生成（Entity、Dao、Service）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;C#暂时只支持 Entity，其余两层因为本人没有接触过 ASP.Net MVC 所以不太能下手&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一些藏得比较深的 bug&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>