Active Record是業務邏輯層中(《企業應用架構模式》將該模式歸爲數據源模式)經常使用的一種框架模式,尤爲在底層數據庫模型匹配業務模型時它特別有用,它是一種以數據庫驅動爲主的框架模式。git
一般,數據庫中的每張表都對應一個業務對象。業務對象表示表中的一行,而且包含數據、行爲以及持久化該對象的工具,此外還有添加新實例和查找對象集合所需的方法。github
在Active Record模式中,每一個業務對象均負責本身的持久化和相關的業務邏輯。數據庫
Active Record模式很是適用於在數據模型與業務模型之間具備 一對一映射關係的簡單應用程序,如博客或論壇。session
由於業務對象與數據庫中的表具備一對一映射關係,並且均具備相同的CRUD方法,因此可使用代碼生成器自動生成業務模型。架構
Active Record模式中的對象一般會包含用來執行數據庫操做的CRUD操做,還有相關驗證及業務相關的計算和檢查功能。app
特別地,典型的Active Record類還包含一些表示數據表中的列的實例屬性和操做於當前對象上的實例方法。Active Record類中還可能包含一些靜態方法,用來操做數據表上的全部記錄。(下面的實戰操做可能會很好的幫助你理解這句話)框架
Active Record的成功依賴於兩個因素:簡單和框架。Active Record概念上理解起來十分的簡單, 不過若手工實現,仍然須要不少代碼。ide
編寫並維護每個類都須要大量的代碼,不過這僅僅是最低的需求,由於你可能還要考慮爲每一個類或者數據表添加一個或多個數據遷移對象(DTO)。工具
不能否認,活動記錄確實在簡單和最終系統的強大方面找到了良好的平衡。且該模式也等到了不少開發商的支持,例如,LINQ-to-SQL和咱們今天的主角--Castle ActiveRecord。post
理論上,開發中還須要一個額外的層存在於對象模型和數據模式之間,一般叫作數據映射層(Data Mapper)。在Active Record中,咱們能夠將該層直接集成在對象中,不過隨着這一層愈來愈複雜,維護成本也在逐漸提升。
Active Record的另一個問題是對象和數據表設計之間的綁定。若你不得不修改數據庫,那麼要同時修改Active Record的對象模型以及全部的相關代碼。
表模式一般就是目前三層框架中流行的以DateTable和DateSet爲載體在各層中傳遞數據,Active Record則是以對象模型、泛型(如IList<Post>)爲載體在各層中傳遞數據。
Castle ActiveRecord 是ActiveRecord 模式的一個實現,Castle ActiveRecord依賴Nhibernate來完成實際的映像。與單純的ActiveRecord 相比,Castle ActiveRecord具備如下特色:
使用Nhibernate,你繁瑣的配置工做多於複雜的映射,而使用ActiveRecord倒是推動你的生產力的一個保證,你沒必要再爲編寫繁冗複雜的映射文件而頭疼,ActiveRecord封裝了NHibernate的操做,使用特性來代替映射文件,不管什麼時候你須要,ActiveRecord都能給你一個Isession實例,它提供的簡潔的O/R映射會讓你爲實現持久化數據層是那麼簡單而驚歎!
官方網址:http://www.castleproject.org/
環境:Windows 8.1+Visual Stidio 2013+Sql Server 2008R2+.Net Framework 4.0
版本:Castle.ActiveRecord-3.0.RC
數據庫:ActiveRecord_Blog
數據表:Post
USE [ActiveRecord_Blog] GO /****** Object: Table [dbo].[Post] Script Date: 11/08/2014 11:12:03 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Post]( [Id] [int] IDENTITY(1,1) NOT NULL, [Subject] [nvarchar](64) NULL, [Text] [nvarchar](1024) NULL, [DateAdded] [datetime] NULL, CONSTRAINT [PK_Posts] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
數據表:Comment
USE [ActiveRecord_Blog] GO /****** Object: Table [dbo].[Comment] Script Date: 11/08/2014 11:11:22 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Comment]( [Id] [int] IDENTITY(1,1) NOT NULL, [Text] [nvarchar](1024) NULL, [Author] [nvarchar](64) NULL, [DateAdded] [datetime] NULL, [PostId] [int] NULL, CONSTRAINT [PK_Comment] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO ALTER TABLE [dbo].[Comment] WITH CHECK ADD CONSTRAINT [FK_Comment_Post] FOREIGN KEY([PostId]) REFERENCES [dbo].[Post] ([Id]) GO ALTER TABLE [dbo].[Comment] CHECK CONSTRAINT [FK_Comment_Post] GO
如圖:
Model-->Castle.ActiveRecord.dll、NHibernate.dll
Web-->Model、Castle.ActiveRecord-3.0.RC中的全部DLL
// 指定數據表 [ActiveRecord("Post")] public class Post : ActiveRecordBase<Post> { // 指定數據表中的主鍵 [PrimaryKey(PrimaryKeyType.Identity, "Id")] public int Id { get; set; } // 指定數據表中的列 [Property("Subject")] public string Subject { get; set; } [Property("Text")] public string Text { get; set; } [Property("DateAdded")] public DateTime DateAdded { get; set; } //一對多 [HasMany(typeof(Comment), Table = "Comment", ColumnKey = "PostId")] public IList<Comment> Comments { get; set; } // 靜態方法,經過主鍵ID查找 public static Post Find(int id) { return FindByPrimaryKey(id); } }
[ActiveRecord("Comment")] public class Comment : ActiveRecordBase<Comment> { [PrimaryKey("Id")] public int Id { get; set; } [Property("Author")] public string Author { get; set; } [Property("Text")] public string Text { get; set; } [Property("DateAdded")] public DateTime DateAdded { get; set; } [Property("PostId")] public int PostId { get; set; } // 多對一,對應Post的的Comments屬性 [BelongsTo(Column = "PostId")] public Post Post { get; set; } }
<?xml version="1.0" encoding="utf-8"?> <activerecord isWeb="true"> <config> <add key="connection.driver_class" value="NHibernate.Driver.SqlClientDriver" /> <add key="dialect" value="NHibernate.Dialect.MsSql2005Dialect" /> <add key="connection.connection_string" value="UID=sa;Password=123456;Initial Catalog=ActiveRecord_Blog;Data Source=." /> <add key="connection.provider" value="NHibernate.Connection.DriverConnectionProvider" /> <add key="proxyfactory.factory_class" value="NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" /> </config> </activerecord>
void Application_Start(object sender, EventArgs e) { // 在應用程序啓動時運行的代碼 AuthConfig.RegisterOpenAuth(); RouteConfig.RegisterRoutes(RouteTable.Routes); InitActiveRecord(); } private void InitActiveRecord() { try { string NHibernateFilePath = Server.MapPath("~/NHibernate.config"); XmlConfigurationSource source = new XmlConfigurationSource(NHibernateFilePath); ActiveRecordStarter.Initialize(source, typeof(Model.Post), typeof(Model.Comment)); } catch (Exception) { throw; } }
public void Add() { Model.Post post = new Model.Post() { Subject = "測試2", Text = "測試內容2", DateAdded = DateTime.Now }; post.Create(); }
public void Update() { Model.Post post = new Model.Post(); post = Model.Post.Find(1); post.Subject = "修改後1"; post.Text = "修改後內容1"; post.Update(); }
public void Delete(int id) { Model.Post post = new Model.Post(); post.Id = 1; post.Delete(); Response.Write("刪除了ID:" + id + "\n\r"); } public void DeleteAll() { Model.Post.DeleteAll(); }
public void Find(int id) { using (new SessionScope()) { Model.Post post = new Model.Post(); post = Model.Post.Find(id); Response.Write(post.Id.ToString() + "\n\r"); Response.Write(post.Subject + "\n\r"); Response.Write(post.Text + "\n\r"); Response.Write(post.DateAdded.ToString() + "\n\r"); Response.Write(post.Comments.FirstOrDefault().Id); } } public void FindAll() { IList<Model.Post> postList = Model.Post.FindAll(); foreach (var post in postList) { Response.Write(post.Id.ToString() + "\n\r"); Response.Write(post.Subject + "\n\r"); Response.Write(post.Text + "\n\r"); Response.Write(post.DateAdded.ToString() + "\n\r"); } }
源碼下載:百度雲