O Castle ActiveRecord é uma implementação do pattern Active Record desenvolvido em .NET em cima do NHibernate.

Ele faz parte do pacote de frameworks do projeto Castle Projet, e tem forte influencia da implementação do Active Record do framework Ruby On Rails.

Entre as muitas características dele vale destacar, a possibilidade de mapeamento de classes via atributos e não dos famigerados arquivos xml e um mecanismo de validação eficiente e flexível.

Criando o projeto

Acesse a página de download do projeto, baixe o arquivo Castle-net-2.0-release-2007-9-20.zip e descompacte em algum diretório da sua preferência.

Em seguida crie um novo projeto web e faça referência as assemblies abaixo:

Castle.ActiveRecord.dll
Castle.Core.dll
Castle.Components.Validator.dll
Castle.DynamicProxy.dll
NHibernate.dll
Iesi.Collections.dll
log4net.dll

Criando a tabela de Contatos

Crie uma base de dados chamada ContatosAR e em seguida crie uma tabela com a estrutura abaixo.

CREATE TABLE [dbo].[Contatos](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[Nome] [varchar](255) NOT NULL,
	[Email] [varchar](255) NOT NULL,
 CONSTRAINT [PK_Contatos] 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]

Criando a classe Contato

Agora vamos criar a classe que vai representar a nossa tabela.

using System;

public class Contato
{
  private int id;
  private string nome;
  private string email;

  public int Id
  {
    get { return id; }
    set { id = value; }
  }

  public string Nome
  {
    get { return nome; }
    set { nome = value; }
  }

  public string Email
  {
    get { return email; }
    set { email = value; }
  }
}

Mapeando a classe Contato

Mapeando a nossa classe para o NHibernate. Só que em vez do xml entra em cena os atributos disponíveis no ActiveRecord.

[ActiveRecord("Contatos")]
public class Contato : ActiveRecordValidationBase<Contato>
{
    private int id;
    private string nome;
    private string email;

    [PrimaryKey(PrimaryKeyType.Native, "Id")]
    public int Id
    {
      get { return id; }
      set { id = value; }
    }

    [Property("Nome")]
    [ValidateNonEmpty("Nome é requirido")]
    [ValidateLength(1, 255, "Nome deve ter no máximo 255 caracteres")]
    public string Nome
    {
      get { return nome; }
      set { nome = value; }
    }

    [Property("Email")]
    [ValidateNonEmpty("E-mail é requirido")]
    [ValidateLength(1, 255, "E-mail deve ter no máximo 255 caracteres")]
    [ValidateEmail("E-mail inválido")]
    public string Email
    {
      get { return email; }
      set { email = value; }
    }
}

Configurando o ActiveRecord

No arquivo Web.Config adicione o código abaixo e altere a chave hibernate.connection.connection_string para apontar para a sua instância do SQL Server.

<?xml version="1.0"?>

<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="hibernate.dialect"
                 value="NHibernate.Dialect.MsSql2005Dialect" />
      <add key="hibernate.connection.provider"
                 value="NHibernate.Connection.DriverConnectionProvider" />
      <add key="hibernate.connection.connection_string"
                 value="Data Source=.;Initial Catalog=ContatosAR;Integrated Security=True" />
    </config>
  </activerecord>
</configuration>

E no arquivo Global.asax adicione o código abaixo.

<%@ Application Language="C#" %>

<%@ Import Namespace="Castle.ActiveRecord" %>
<%@ Import Namespace="Castle.ActiveRecord.Framework" %>
<%@ Import Namespace="Castle.ActiveRecord.Framework.Config" %>

<script runat="server">
    void Application_Start(object sender, EventArgs e)
    {
        IConfigurationSource source = ActiveRecordSectionHandler.Instance;
        ActiveRecordStarter.Initialize(source, typeof(Contato));
    }
</script>

Listando os contatos

Agora, com o ActiveRecord configurado, vamos criar uma página para listar todos os contatos cadastrados na base de dados (nenhum até o momento).

<asp:GridView ID="gvContatos" AutoGenerateColumns="false" runat="server">
    <Columns>
        <asp:HyperLinkField DataNavigateUrlFields="Id"
                DataNavigateUrlFormatString="EditarContato.aspx?Id={0}"
		DataTextField="Nome" HeaderText="Nome" />

	    <asp:BoundField DataField="Email" HeaderText="E-mail" />
    </Columns>
</asp:GridView>

ListarContatos.aspx.cs

public partial class ListarContatos : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        gvContatos.DataSource = Contato.FindAll();
        gvContatos.DataBind();
    }
}

Inserindo um contato

Montando o formulário de inserção. De propósito vou deixar para fazer a validação no servidor.

<h3>Novo contato</h3>

<asp:Panel ID="pnMensagem" runat="server" Visible="false">
    <asp:Label ID="lblMensagem" runat="server" />
</asp:Panel>

<p>
    <asp:Label ID="lblNome" runat="server" AssociatedControlID="txtNome">Nome:</asp:Label>
    <asp:TextBox ID="txtNome" runat="server" Columns="40" MaxLength="255"></asp:TextBox>
</p>

<p>
    <asp:Label ID="lblEmail" runat="server" AssociatedControlID="txtEmail">E-mail:</asp:Label>
    <asp:TextBox ID="txtEmail" runat="server" Columns="40" MaxLength="255"></asp:TextBox>
</p>				

<asp:Button ID="btnSalvar" runat="server" OnClick="btnSalvar_Click" Text="Salvar" />
ou <a href="ListarContatos.aspx">Voltar</a>

NovoContato.aspx.cs

public partial class NovoContato : System.Web.UI.Page
{
    protected void btnSalvar_Click(object sender, EventArgs e)
    {
        pnMensagem.Visible = true;
        lblMensagem.Text = "";

        Contato contato = new Contato();

        contato.Nome = txtNome.Text;
        contato.Email = txtEmail.Text;

        if (contato.IsValid())
        {
            contato.Create();

            lblMensagem.Text = "Contato criado com sucesso.";

            txtNome.Text = "";
            txtEmail.Text = "";
        }
        else
        {
            foreach (string s in contato.ValidationErrorMessages)
                lblMensagem.Text += s;
        }
    }
}

Editando um contato

<h3>Editar contato</h3>

<asp:Panel ID="pnMensagem" runat="server" Visible="false">
    <asp:Label ID="lblMensagem" runat="server" />
</asp:Panel>

<p>
    <asp:Label ID="lblNome" runat="server" AssociatedControlID="txtNome">Nome:</asp:Label>
    <asp:TextBox ID="txtNome" runat="server" Columns="40" MaxLength="255"></asp:TextBox>
</p>

<p>
    <asp:Label ID="lblEmail" runat="server" AssociatedControlID="txtEmail">E-mail:</asp:Label>
    <asp:TextBox ID="txtEmail" runat="server" Columns="40" MaxLength="255"></asp:TextBox>
</p>				

<asp:Button ID="btnSalvar" runat="server" OnClick="btnSalvar_Click" Text="Salvar" />
ou <a href="ListarContatos.aspx">Voltar</a>

EditarContato.aspx.cs

public partial class EditarContato : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            Contato contato = Contato.Find(Convert.ToInt32(Request.QueryString["Id"]));

            txtNome.Text = contato.Nome;
            txtEmail.Text = contato.Email;
        }
    }

    protected void btnSalvar_Click(object sender, EventArgs e)
    {
        pnMensagem.Visible = true;
        lblMensagem.Text = "";

        Contato contato = Contato.Find(Convert.ToInt32(Request.QueryString["Id"]));

        contato.Nome = txtNome.Text;
        contato.Email = txtEmail.Text;

        if (contato.IsValid())
        {
            contato.Update();

            lblMensagem.Text = "Dados do contato atualizados com sucesso.";
        }
        else
        {
            foreach (string s in contato.ValidationErrorMessages)
                lblMensagem.Text += s;
        }
    }
}

Código do projeto

O código do projeto está disponivel para download.

Ele foi desenvolvido usando o Microsoft Visual Web Developer 2008 Express Edition com o SQL Server Express 2005.

Em breve

Depois dessa passada superficial vou tentar preparar uma série de posts detalhando mais as funcionalidades do framework.