The Question: What if I still want to use ActiveRecord, but don’t want all my objects to inherit from ActiveRecordBase or ActiveRecordBase<> because of all the functionality I already have in my base object?
The Answer: ActiveRecordMediator.
//Dramatisation ends here.
The mediator class provides a very clean way to still make use of all the features provided by ActiveRecord, making use of the ActiveRecord attributes, but affording you the freedom of inheriting from your own base class. A description of my hypothetical class design could be:
- The base class (BaseObject) is abstract
- It has an abstract property called "Id"
- It exposes two other properties called "IsNew" and "IsDeleted"
- The "IsDeleted" property is decorated by an ActiveRecord Property attribute
- All classes that inherit the BaseObject should override "Id" and use it as the primary key
- All classes/database table have an "IsDeleted" column, and is provided from the base class
Take a look at the example below which follows the statements above:
public abstract class BaseObject
{
public abstract int Id { get; set; }
public bool IsNew { get {return (Id == 0);}}
[Property("IsDeleted", ColumnType = "Boolean", NotNull = true)]
public bool IsDeleted { get; set; }
}
[ActiveRecord ("Customer")]
public class Customer : BaseObject
{
[PrimaryKey (PrimaryKeyType.Identity, Column="CustomerId")]
public override int Id {get; set;}
[Property ("CustomerName")]
public virtual string CustomerName {get; set;}
[HasMany(typeof (Address))]
IList<Address> Addresses {get; set;}
}
[ActiveRecord("Address")]
public class Address : BaseObject
{
[PrimaryKey(PrimaryKeyType.Identity, Column = "AddressId")]
public override int Id { get; set; }
public string FullAddress {get; set;}
[BelongsTo (Type=typeof (Customer), Column="CustomerId")]
public Customer Customer {get; set;}
}
As you can see, I've decorated all the necessary fields with ActiveRecord property and primary key attributes, but none of them inherit from ActiveRecordBase. This means thatthe call to Customer.SaveAndFlush() can't be made, for example, as it normally would. Instead, a call to the ActiveRecordMediator.SaveAndFlush method is made to save the entity.
Customer c = new Customer() { CustomerName = "The Darksider" };
ActiveRecordMediator<T>.SaveAndFlush(entity);
In another example, like when you're fetching a list of entities, you can make the call as follows:
IList<Customer> customers = ActiveRecordMediator<Customer>.FindAll();
If you're really comfortable with the methods provided by inheriting ActiveRecordBase, but can't get around not having your own base class, consider implementing your data access methods in the base class, or even better, with extension methods:
public static class Extensions
{
public static void SaveAndFlush(this BaseObject entity)
{
ActiveRecordMediator<BaseObject>.SaveAndFlush(entity);
}
}