views:

62

answers:

1

Is it possible to use generic support with single table inheritance, and still be able to FindAll of the base class?

As a bonus question, will I be able to use ActiveRecordLinqBase<> as well? I do love those queries.

More detail: Say I have the following classes defined:

public interface ICompany
{
    int ID { get; set; }
    string Name { get; set; }
}

[ActiveRecord("companies", 
  DiscriminatorColumn="type", 
  DiscriminatorType="String", 
  DiscriminatorValue="NA")]
public abstract class Company<T> : ActiveRecordBase<T>, ICompany
{
    [PrimaryKey]
    private int Id { get; set; }

    [Property]
    public String Name { get; set; }
}

[ActiveRecord(DiscriminatorValue="firm")]
public class Firm : Company<Firm>
{
    [Property]
    public string Description { get; set; }
}

[ActiveRecord(DiscriminatorValue="client")]
public class Client : Company<Client>
{
    [Property]
    public int ChargeRate { get; set; } 
}

This works fine for most cases. I can do things like:

var x = Client.FindAll();

But sometimes I want all of the companies. If I was not using generics I could do:

var x = (Company[]) FindAll(Company);
Client a = (Client)x[0];
Firm b = (Firm)x[1];

Is there a way to write a FindAll that returns an array of ICompany's that can then be typecast into their respective types?
Something like:

var x = (ICompany[]) FindAll(Company<ICompany>);
Client a = (Client)x[0];

Or maybe I am going about implementing the generic support all wrong?

A: 

How about this:

[ActiveRecord("companies", 
  DiscriminatorColumn="type", 
  DiscriminatorType="String", 
  DiscriminatorValue="NA")]
public abstract class Company : ActiveRecordBase<Company>, ICompany {
    [PrimaryKey]
    private virtual int Id { get; set; }

    [Property]
    public virtual String Name { get; set; }
}

[ActiveRecord(DiscriminatorValue="firm")]
public class Firm : Company {
    [Property]
    public virtual string Description { get; set; }
}

[ActiveRecord(DiscriminatorValue="client")]
public class Client : Company {
    [Property]
    public virtual int ChargeRate { get; set; } 
}

var allClients = ActiveRecordMediator<Client>.FindAll();
var allCompanies = ActiveRecordMediator<Company>.FindAll(); // Gets all Companies (Firms and Clients). Same as Company.FindAll();

Note that you can't just downcast your Companies as Clients or Firms, you need to use proper polymorphism or a visitor. See this for an explanation.

Mauricio Scheffer
I would prefer to avoid needing the mediator for all my sub-classes. I only need to find all companies on occassion. I would use the generic functions on the firms and clients all the time. And yea, I was using the downcast to show that the array contained an upcasted form of Client. It didn't just contain Company's. I probobly wouldn't assume the first object in an unordered array was a Client either.
oillio
If you want to be able to do `Client.FindAll()` you'll have to implement the static method in Client, using `ActiveRecordMediator<Client>`
Mauricio Scheffer