上一篇主要介绍了一些设计原则和模式,本章来详细介绍一下Active Record模式,一个Blog小程序。
导航到http://sourceforge.net/projects/castleproject/files/ActiveRecord/3.0/Castle.ActiveRecord-3.0.RC.zip/download下载ActiveRecord项目的最新版。
创建名为 Terminator.Practice.ActiveRecord 的解决方案,添加名为 Terminator.Practice.ActiveRecord.Model 的C#类库和一个名为 Terminator.Practice.ActiveRecord.UI.MVC 的MVC应用程序(demo中使用的是MVC2.0)。
在解决方案创建一个名为Lib的文件夹,将Castle ActiveRecord下载文件放入其中,为Model项目添加Lib文件夹下的所有引用,MVC项目需要添加Castle.ActiveRecord.dll、NHibernate.dll以及对Model项目的引用。
创建Blog.mdf数据库,两张表Posts(Id,Subject,Text,DateAdd)和Comments(Id,Text,Author,DateAdd,PostId)
向Model项目添加一个Comment类:
using System; using Castle.ActiveRecord; namespace Terminator.Practice.ActiveRecord.Model { [ActiveRecord("Comments")] public class Comment : ActiveRecordBase<Comment> { [PrimaryKey] public int Id { get; set; } [BelongsTo("PostID")] public Post Post { get; set; } [Property] public string Text { get; set; } [Property] public string Author { get; set; } [Property] public DateTime DateAdded { get; set; } } }
用来修饰Comment类属性的特性会提示框架这些属性与数据库表的列相匹配。然后,Castle ActiveRecord框架使用该信息来自动完成业务实体持久化和检索,而不必要编写冗长的sql语句。
添加Post类:
using System; using System.Collections.Generic; using Castle.ActiveRecord; using Castle.ActiveRecord.Queries; namespace Terminator.Practice.ActiveRecord.Model { [ActiveRecord("Posts")] public class Post : ActiveRecordBase<Post> { [PrimaryKey] public int Id { get; set; } [Property] public string Subject { get; set; } [Property] public string Text { get; set; } public string ShortText { get { if (Text.Length > 20) return Text.Substring(0, 20) + "..."; return Text; } } [HasMany] public IList<Comment> Comments { get; set; } [Property] public DateTime DateAdded { get; set; } public static Post FindLastestPost() { SimpleQuery<Post> q = new SimpleQuery<Post>(@"from Post p order by p.DateAdded desc"); return q.Execute()[0]; } } }
这就是模型和数据访问的全部代码。非常的简单,这也正是Ruby on Rails开发者们一直炫耀的技术。
现在可以构造网站来显示帖子和评论。
添加一个名为BlogController的控制器:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web.Mvc; 5 using Terminator.Practice.ActiveRecord.Model; 6 7 namespace Terminator.Practice.ActiveRecord.UI.MVC.Controllers 8 { 9 public class BlogController : Controller 10 { 11 // GET: /Blog/ 12 public ActionResult Index() 13 { 14 Post[] posts = Post.FindAll(); 15 16 if (posts.Any()) 17 { 18 ViewData["AllPosts"] = posts; 19 ViewData["LatestPost"] = Post.FindLastestPost(); 20 return View(); 21 } 22 return Create(); 23 } 24 25 // POST: /Blog/ 26 [AcceptVerbs(HttpVerbs.Post)] 27 public ActionResult CreateComment(string Id, FormCollection collection) 28 { 29 int postId; 30 int.TryParse(Id, out postId); 31 Post post = Post.Find(postId); 32 33 Comment comment = new Comment(); 34 comment.Post = post; 35 comment.Author = Request.Form["Author"]; 36 comment.DateAdded = DateTime.Now; 37 comment.Text = Request.Form["Comment"]; 38 39 comment.Save(); 40 41 return Detail(post.Id.ToString()); 42 } 43 44 // GET: /Blog/Detail/1 45 public ActionResult Detail(string Id) 46 { 47 ViewData["AllPosts"] = Post.FindAll(); 48 49 int postId; 50 int.TryParse(Id, out postId); 51 52 ViewData["LatestPost"] = Post.Find(postId); 53 54 return View("Index"); 55 } 56 57 // GET: /Blog/Create 58 public ActionResult Create() 59 { 60 return View("AddPost"); 61 } 62 63 // POST: /Blog/Create 64 [AcceptVerbs(HttpVerbs.Post)] 65 public ActionResult Create(FormCollection collection) 66 { 67 Post post = new Post(); 68 post.DateAdded = DateTime.Now; 69 post.Subject = Request.Form["Subject"]; 70 post.Text = Request.Form["Content"]; 71 post.Save(); 72 73 return Detail(post.Id.ToString()); 74 } 75 76 public JsonResult Delete(int id) 77 { 78 Post post = Post.Find(id); 79 IList<int> commentIds = post.Comments.Select(item => item.Id).ToList(); 80 //先删除评论 81 Comment.DeleteAll(commentIds); 82 //删除博客 83 Post.DeleteAll("Id=" + id); 84 return Json(1); 85 } 86 87 public JsonResult DeleteComment(int id) 88 { 89 Comment.DeleteAll("Id="+id); 90 return Json(1); 91 } 92 } 93 }
关于aspx页面以及webconfig配置的代码请参照源码。
下面对Global.asax文件进行更改:
using System.Configuration; using System.Web.Mvc; using System.Web.Routing; using Castle.ActiveRecord.Framework; using Terminator.Practice.ActiveRecord.Model; namespace Terminator.Practice.ActiveRecord.UI.MVC { // Note: For instructions on enabling IIS6 or IIS7 classic mode, // visit http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Blog", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); IConfigurationSource source = ConfigurationManager.GetSection("activeRecord") as IConfigurationSource; Castle.ActiveRecord.ActiveRecordStarter.Initialize(source, typeof(Post), typeof(Comment)); } } }
要让Castle ActiveRecord运行起来还需要对webconfig进行配置,下面列出片段:
<configuration> <configSections> <section name="activeRecord" type="Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord"/> </configSections> <activeRecord isWeb="true"> <config> <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver"/> <add key="dialect" value="NHibernate.Dialect.MsSql2008Dialect"/> <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider"/> <add key="connection.connection_string" value="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Blog.mdf;Integrated Security=True;User Instance=True"/> <add key="proxyfactory.factory_class" value="NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle"/> </config> </activeRecord> <appSettings/> <connectionStrings> <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient"/> </connectionStrings> .....其他配置内容 </configuration>
关于css和aspx页面的内容这里没有讲的很详细,以下是效果图