- Posted by justin on February 7, 2007
As I have been playing with ActiveRecord (http://www.castleproject.org ) one of the things I need to do was to bind a ActiveRecord class to a datagrid to view data. I did not need to worry about insert/update/delete in the grid. So you may be saying big deal, this is easy. You are correct if you are just binding primitive types (int, string, etc). However, if your ActiveRecord class has any complex objects such as other ActiveRecord class then you can not by default get to the data by just setting the DataSource to the results of the FindAll() method.
To solve the databinding problem, I found ObjectDataSource worked really well. On the datagrid I wanted to display a collection of WorkOrders and the Tool.ToolName value as a column. To get the workorders, I used the ActiveRecord FindAll() method.
ActiveRecord Class:
using System;
using System.Collections.Generic;
using System.Text;
using Castle.ActiveRecord;
namespace MyARDemo
{
[ActiveRecord("WorkOrders")]
[System.ComponentModel.DataObject]
public partial class WorkOrder : DomainObject<WorkOrder>
{
private DateTime _createdOn;
private string _createdOnShift;
private string _createdOnWorkWeek;
private string _description;
private DateTime _lastUpdatedOn;
private int _id;
private Tool _tool;
private User _createdByUser;
private User _lastUpdatedByUser;
public WorkOrder()
{
}
[PrimaryKey(PrimaryKeyType.Native, "WorkOrderID", Access = PropertyAccess.FieldLowercaseUnderscore)]
public int ID
{
get { return _id; }
set { _id = value; }
}
[Property(NotNull = true, Column = "CreatedOn")]
public DateTime CreatedOn
{
get { return _createdOn; }
set { _createdOn = value; }
}
[Property(NotNull = true, Length = 2, Column = "CreatedOnShift")]
public string CreatedOnShift
{
get { return _createdOnShift; }
set { _createdOnShift = value; }
}
[Property(NotNull = true, Length = 6, Column = "CreatedOnWorkWeek")]
public string CreatedOnWorkWeek
{
get { return _createdOnWorkWeek; }
set { _createdOnWorkWeek = value; }
}
[Property(NotNull = true, SqlType = "VARCHAR(MAX)", Column = "Description")]
public string Description
{
get { return _description; }
set { _description = value; }
}
[Property(NotNull = true, Column = "LastUpdatedOn")]
public DateTime LastUpdatedOn
{
get { return _lastUpdatedOn; }
set { _lastUpdatedOn = value; }
}
[BelongsTo("ToolID")]
public Tool Tool
{
get { return _tool; }
set { _tool = value; }
}
[BelongsTo("CreatedByUserID")]
public User CreatedByUser
{
get { return _createdByUser; }
set { _createdByUser = value; }
}
[BelongsTo("LastUpdatedByUserID")]
public User LastUpdatedByUser
{
get { return _lastUpdatedByUser; }
set { _lastUpdatedByUser = value; }
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Castle.ActiveRecord;
namespace MyARDemo
{
[ActiveRecord("Tools")]
public partial class Tool : DomainObject<Tool>
{
private bool _customized;
private bool _deleted;
private int _lastUpdatedByID;
private DateTime _lastUpdatedOn;
private string _toolName;
private int _id;
private IList<WorkOrder> _workOrders;
public Tool()
{
_workOrders = new List<WorkOrder>();
}
[PrimaryKey(PrimaryKeyType.Native, "ToolID", Access = PropertyAccess.FieldLowercaseUnderscore)]
public int ID
{
get { return _id; }
set { _id = value; }
}
[Property(NotNull = true, Column = "Customized")]
public bool Customized
{
get { return _customized; }
set { _customized = value; }
}
[Property(NotNull = true, Column = "Deleted")]
public bool Deleted
{
get { return _deleted; }
set { _deleted = value; }
}
[Property(NotNull = true, Column = "LastUpdatedByID")]
public int LastUpdatedByID
{
get { return _lastUpdatedByID; }
set { _lastUpdatedByID = value; }
}
[Property(NotNull = true, Column = "LastUpdatedOn")]
public DateTime LastUpdatedOn
{
get { return _lastUpdatedOn; }
set { _lastUpdatedOn = value; }
}
[Property(NotNull = true, Length = 50, Column = "ToolName")]
public string ToolName
{
get { return _toolName; }
set { _toolName = value; }
}
[HasMany(typeof(WorkOrder), Lazy = true, Table = "WorkOrders", ColumnKey="ToolID", Inverse=true)]
public IList<WorkOrder> WorkOrders
{
get { return _workOrders; }
set { _workOrders = value; }
}
}
}
WebForm Code:
On the DataGrid, I left AutoGeneration on for the primitive types and for the complex type Tool.ToolName, I added a Templated Column.
<Columns>
<asp:TemplateField HeaderText="Tool">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("Tool.ToolName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
I know that there is a ARDataSource project in the AR Contrib but it would not compile for me and since I did not need the more than a ReadOnly view I did not work to fix the errors. I may ultimately end up writing my own data source control. There are several articles that talk about how to do it and even some code from other ORM data source controls.
Nikhil Kothari's Weblog : Data Source Controls Summary: http://www.nikhilk.net/DataSourceControlsSummary.aspx
Vault of Thoughts - .NET Blog - How To Use MyObjectDataSource: http://vaultofthoughts.net/HowToUseMyObjectDataSource.aspx
NHibernateDataSource: A DataSourceControl for ASP.NET 2.0 - The Code Project - ASP.NET: http://www.codeproject.com/useritems/NHibernateDataSource.asp
Paul Wilson's .NET Blog : Introducing the WilsonORMapper DataSource Control: http://weblogs.asp.net/pwilson/archive/2006/05/17/446919.aspx