工作的程序员

入门橡树:数据库交互

Ted Neward

欢迎回来。我一直走通过入门橡木,动态方法对 Web 开发,同时仍保留了 C# 语言、 ASP.NET MVC 框架和你享受的 Microsoft.NET 框架的其余部分体现在 Ruby 和 Node.js 世界的想法。橡木的实质是"快速反馈、 无摩擦发展和低仪式上,"在项目创建者埃米尔 Rajan 的单词。

当我离开后时,橡树被抱怨它不能连接到的数据­基地。在本专栏中,我会教你怎么进行以下操作:橡木布线到 SQL Server 实例、 将另一个相关的类型添加到系统 (评论上的博客条目)、 生成的数据库在橡木、 涉及两种类型一起使用橡木,和看到橡树和其生成系统如何处理数据库交互。

当我们离开我们的英雄......

最后一次橡木当时正在运行,它弹出错误消息和乐于助人的说明性文本,摘录其中示图 1。(作为提醒,如果你是在最后一列后 — 在 msdn.microsoft.com/magazine/dn532208— 你需要关闭服务器和助手转轮踢.)我走的更远之前,请注意如何橡木不是只显示异常堆栈跟踪和留给我发现或研究什么可能会引起问题。它实际上试图诊断问题并提出可能的解决办法:在这种情况下,"更新 web 配置与您的服务器实例"。


图 1 橡木项目帮助窗口出现错误之后引发。

果然,快速浏览一下 web.config 文件我捡简单的占位符是那里,指向"(本地)"的数据源,可能会为很多的配置,根据本地 SQL Server 实例的配置方式工作的"热身"创业板示。也就是说,它是,那些微不足道的 LocalDB 在连接字符串中删除,因为它是放在远程 SQL Server 字符串 (或 Windows Azure SQL 数据库中,如果它是可取的在云计算中保留数据)。我喜欢用 LocalDB,通常是只是一个连接字符串的"服务器 = (localdb) \v11.0;Integrated 安全 = true"探索这样的因为它是小,很容易清理。无论您使用的 SQL 连接只是将它插入 < 配置 > / < connectionStrings > / < 添加 > 元素,并刷新页面。事实上,橡树有一耙 (Ruby 生成工具) 任务为你做这些跨代码库:"耙 update_db_server [(localdb) \\v11.0]"(反斜杠需要转义)。

呃......休斯顿吗?

不幸的是,当再次运行,橡木的行为仿佛一切都没有改变。并且不幸的是,那是完全真实的。助手不看着更改 web.config 文件中,似乎只有源代码文件。考虑到如何很少更改 web.config 文件,这不是世界末日,但它不会放小抽筋什么否则是一个非常轻松的过程。若要获取助手承认该项目已经改变,你只需要触发的一些重要的文件,例如 HomeController.cs 或一些其他源文件保存。可使用两种方式查看:切换到该文件、 在文件中选择一个随机的地方、 按下空格键和删除这个空间 (该文件是"脏"和力量保存说服 Visual Studio),或只是手动的序幕耙从命令提示符。

一旦这样做,刷新浏览器带来了不同的错误 ("无效的对象名称 '博客'"),和你正视到世界的数据库迁移。

数据、 数据、 数据 !

象其概念性的前辈,橡树想要为你管理数据库和数据库架构,因此数据库可以保持更多或更少"隐藏"从您的视图。在这种情况下,橡树不想只是"自动神奇"工艺数据库从稀薄的空气,因为你可能会有一些应如何架构的看法 — 即使你不,数据库管理员经常做。(谁能赢得这场战斗,或谁应该赢得这场战斗,是一个讨论最好了啤酒 — 最好是很久之后该项目已售出.)

在橡木,做播种数据库使用一个特定的控制器,SeedController,发现嵌套在 SeedController.cs HomeController 的旁边。该文件包含一个定义为 SeedController 已经,但是 — 更重要的是为您的目的 — 它还包含一个架构类,这将有助于建立架构和一些示例数据 (可选),放的位置的必要步骤。铭记着,顺便说一句,那橡树的默认约定是多元名称的数据库表中的存储对象,所以博客的对象将存储在一个名为博客表。图 2 显示的架构类。

图 2 的架构类

 

public class Schema
{
  // This is the method you'll want to alter
  public IEnumerable<Func<dynamic>> Scripts()
  {
    // Replace all content inside of the Scripts() method with this line
    yield return CreateBlogsTable; // Return just the pointer to the function
  }
  public string CreateBlogsTable() // Here is the function definition
  {
    // This is an example, your table name may be different
    // For more information on schema generation check out the Oak wiki
    return Seed.CreateTable("Blogs",
      Seed.Id(),
      new { Name = "nvarchar(255)" },
      new { Body = "nvarchar(max)" }
    );
  }
  public void SampleEntries()
  {
  }
  public Seed Seed { get; set; }
  public Schema(Seed seed) { Seed = seed; }
}

注意奇怪的"收益回报"的脚本方法中使用。 对于那些你也没弄明白这在 C# 2.0 中做了什么,"产量返回"创建的对象的一个匿名的"流"和手回 IEnumerable < T > 指向该流。 在这特定的情况下,它是一个流的功能,并在此特定的方案,它是一个函数 (CreateBlogsTable) 的流。 本质上,您要设置的操作 (Func < 动态 > 流 实例) 代表如何创建数据库和橡树将采取每个行动或函数交回从这流并执行它。 这种方式,当有新的更改对架构来发挥作用,这种变化可以在一个新的函数中捕获 ("CreateComments­表中,"如果你将) 和简单地添加到列表中。 如果需要,你也可以通过,所以调用第一个函数 Version1,第二个 Version2"版本"的数据库架构。 橡木维基已在数据库迁移的详细信息 bit.ly/1bgods5

(对于那些记得我"多模式化.NET"系列,在开始 msdn.microsoft.com/magazine/ff955611,是的这是相当功能面向的方式解决这个问题.)

Seed.Id 函数创建规范的主键列:自动递增的整数值标记为主键。 橡木 wiki (bit.ly/1iKfcIb) 包含关于使用种子类到创建数据库引用这样做,但总是有做直 SQL,如果所需的特设备用:

public IEnumerable<string> AdHocChange()
{
  var reader = "select * from SampleTable".ExecuteReader();
  while (reader.Read())
  {
    // Do stuff here like yield return strings
  }
    var name = "select top 1 name from sysobjects"
      .ExecuteScalar() as string;
    yield return "drop table SampleTable";
    yield return "drop table AnotherSampleTable";
  }

作为"回报"的另一种方法来调用,添加的 AdHocChange 方法和橡木会愉快地进行,以及这些命令。 (请注意是否你失去对该 wiki 链接的跟踪,橡树它的消息中包括错误/帮助它显示)。

我不能没有粘土做砖 !

顺便说一句,如果需要一些种子数据的数据库,这也是 SeedController 的责任的一部分并且再次它下跌到要做到,这次是通过 SampleEntries 方法的架构类。 由于此系统没有任何真正的种子需要数据,在这里,我就让这单独。

SeedController 编译后,助手将重新部署项目,但像大多数控制器不会获取激活它直到命中与一个 HTTP 请求。 如果你没超过 SeedController 一眼,看一眼。 它出口四个职位终结点:PurgeDB、 出口,所有和 SampleEntries。 虽然你当然可以自己打终结点,这是最佳左到自动化重复任务的那种 — 在橡木的手段的情况下,犁耙。 果然,"耙子重置"将删除所有表和重新生成的架构 (它不会发到 /seed/PurgeDB 和/种子 / 所有然后另一个职位),和"耙子样本"将都删除表、 重新生成架构和生成示例数据 (邮政 /seed/SampleEntries)。 只是为了保持完整性,顺便说一句,是"耙出口"(或邮政 /seed/export) 将返回到使用做那些事情的 SQL 语句。

(卷曲或红宝石可以从命令行一线行使,顺便做一个职位。 Rakefile.rb 文件的示例,说明如何做使用 Net::HTTP::post_from 一职,是很容易剪切并粘贴到另一个别的文件,如果你不想把它埋掉里面的 Rakefile。 或者你可以用这个作为网关往学习 Ruby 的药物。 没有人判断)。

它还活着 !

假设有没有错别字,耙子重置操作完成后,在浏览器中的刷新带来工作的网页,(对于博客标题) 的简单的文本字段和一个"提交"按钮。 进入一个新的博客标题将生成一个错误,但是 — 虽然博客存在,有种假设 (基于什么是 Index.cshtml 视图中) 也是一种与博客相关的东西称为注释。

在占主导地位,博客引擎世界简单的关系模型,博客有评论一对多的关系。 我想要模型,所以首先我需要一种数据类型对于评论的对象,再是简单的脑死亡,以及,此系统中。 事实上,因为评论是 (类似博客的对象) 基本上是动态对象,不带任何有趣元素给他们,他们甚至不用模型类定义 — 股票的所有动态对象 (双子星座类型,为那些在记住我的 2013 年 8 月专栏、"会动态与双子座图书馆," msdn.microsoft.com/magazine/dn342877) 是精细。

(是的如果你还没有种"我们是从堪萨斯,托托很长的路"的在现在之前的时刻,这是绝对时间停下来思考:您正在使用业务对象你从来不来定义其类型)。

若要描述关系的博客的评论,但是,有做两件事。 第一,评论需要一个存储库中 (就像博客那样在我的最后一列):

public class Comments : DynamicRepository
{
}

更重要的是,博客类需要略有革新,以捕获一对多的关系,既有直接 (博客拥有的注释对象,在这种情况下意味着作为字段有一个注释对象的集合),和间接 (所以橡树知道 Blog 和发表评论的对象连接到数据库中,以及如何)。 这通过引入一种新方法,同伙,描述的关系,如中所示图 3

图 3 描述的博客和评论的一对多关系

public class Blog : DynamicModel
{
  Blogs blogs = new Blogs();
  // Define comments
  Comments comments = new Comments();
  public Blog() { }
  public Blog(object dto) : base(dto) { }
  // Add an Associates method to add the Comments() method
  IEnumerable<dynamic> Associates()
  {
    // And define the association
    // For othere examples of associations check out the Oak wiki
    yield return new HasMany(comments);
  }
}

正如您所看到的它不是真的那么离谱说你需要做的:该模型很密切匹配一个博客的抽象概念。 这是可以看到的美容和使用动态技术的权力。 这一变化 (同伙方法做"收益回报"的 HasMany) 实际上触发被添加到博客的三种新方法 — 评论、 CommentIds 和 NewComment — 以支持注释的关系对象与博客对象,所有这些都是纯棚架,通常会要求你写那些方法"硬道路的"是你使用的正常的、 非动态的 C#。 自然,不过,这一切的工作针对数据库,您需要备份它带有数据库说明的注释表,这意味着你回来到 SeedController (并随后耙子重置),作为显示在图 4

图 4 数据库描述的意见表

public class Schema{
  public IEnumerable<Func<dynamic>> Scripts()
  {
    yield return CreateBlogsTable;
    yield return CreateCommentsTable;
  }
  public string CreateBlogsTable() // Here is the function definition
  {
    return Seed.CreateTable("Blogs",
      Seed.Id(),
      new { Name = "nvarchar(255)" },
      new { Body = "nvarchar(max)" }
    );
  }
  public string CreateCommentsTable() // Here is the function definition
  {
    return Seed.CreateTable("Comments",
      Seed.Id(),
      new { BlogId = "int", ForeignKey = "Blogs(Id)" },
      new { Body = "nvarchar(max)" }
    );
  }
}

因为我在这里顺便说一下,我将添加几个博客条目,只是为了炫耀如何使用 SampleEntries 方法。 它是比你想象的要容易得多,如中所示图 5

图 5 添加博客条目

public void SampleEntries(){
  var blog1 = new // Store the ID
  {
    Name = "Hello, Oak Blog",
    Body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
  }.InsertInto("Blogs");
  new { Body = "great job!", BlogId = blog1 }.InsertInto("Comments");
  new
  {
    Name = "Here are cat pictures!",
    Body = "Meowem hisum collar sit amet, addipisces lick."
  }.InsertInto("Blogs");
}

再一次动态对象和扩展方法的使用也使其几乎不看像 C# 了。 (在这种情况下,你不去创造一样具有自动生成属性标题和正文,创建匿名对象的一个实例,然后使用扩展方法 InsertInto 做实际插入一个动态对象)。而且,顺便说一句,陷阱 blog1 本地变量中的对象的唯一理由是使它可以使用作为博客的 ID 值为对它的评论。

继续。 刷新与耙示例数据库,然后刷新浏览器。

下一主题:用户输入的验证

这将变成一些有趣的东西,如果不是已经。 你没有模型定义了类型,但您有它的工作模型和数据库存储。 (尽管它是公平的建议的架构类中的特设方法重复的使用可以轻松地转到 SQL 脚本) 涉及任何 SQL 脚本,而且很重要的是要指出所有的代码做的一切都是 (仍然) 藏以源代码形式橡木文件夹中的基架的项目,以防您需要调试或感觉就像浏览。

仍有几个事情尚未做,如验证用户输入,以确保它可以是存储之前, 的所有好的和正确但下一次是一个很好的主题。

编码愉快 !

Ted Neward 是的校长 Neward & 同伙 LLC。他已写一百多篇和创作和合著十几本书,其中包括"专业 F # 2.0"(Wrox,2010年)。他是 F # 最有价值球员,并在世界各地的会议上讲话。他征求意见,并定期导师 — 联系到他在 ted@tedneward.com 如果你感兴趣让他来与您的团队一起工作或阅读他的博客在 blogs.tedneward.com

由于以下的技术专家对本文的审阅:埃米尔 Rajan (橡木项目创建者)
埃米尔 Rajan 是出现在.Net 岩石、 放牧的代码和 Hanselminutes 的发展社区的活跃成员。 他在许多具有专门知识。NET 的 Web 框架,其他体系结构中,红宝石、 JavaScript (前端和 NodeJS),iOS 和 F #。 他是总要争取更好的通过开放源代码捐款行业、 独立咨询和博客 (amirrajan.net) 和可以在达成 ar@amirrajan.net."