In trying to implement the repository pattern I've run into a minor problem that I'm concerned actually belies bigger issues.
I've got a DatabaseEntity<T>
which I'm using to handle all the basic CRUD operations and from which all other classes that need to be stored in a database will descend from. It is working fine for classes that inherit directly from it, however when using it with classes that have an intermediate parent I've run into a problem.
Suppose I have three other classes, Parent, ChildA and ChildB and and the inheritance looks like:
DatabaseEntity
|
Parent
| |
ChildA ChildB
Also suppose that DatabaseEntity<T>
has a method with the following signature:
public static T FindBy(int id)
The issue I'm having is when I try something like:
ChildA Foo = ChildA.FindBy(SomeID);
I get a compiler error telling me that there's no implicit conversion from a Parent to a ChildA. This is because Parent is the class that's being passed in for the type parameter to DatabaseEntity for both ChildA and ChildB. Easy fix I think, just add a type parameter to Parent thus passing through the appropriate type. Only wait a second, then I'll have to explicitly define the subtype any time I'm using Parent which ruins any polymorphism. No, on second thought maybe that's not such a great fix.
I think that I could just drop the type parameter on the class DatabaseEntity itself and have each method require a type parameter but then I'd have to do something like:
ChildA Foo = ChildA.FindBy<ChildA>(SomeID);
While that compiles, it seems less clean and certainly requires more typing. Visual Studio asks if I'm missing a cast and while its true I could just cast my first example its only a matter of time before I accidentally type out:
ChildB Foo = (ChildB) ChildA.FindBy(SomeID)
I'm not especially pleased with any of the solutions I've thought of so far and I'm hoping someone here can point out an elegant one that I've missed.
In the general case, a generic type could be both a supplier and a consumer of its type parameters, which means that the type we get by casting the type parameter (up or down) cannot be either a subtype or a supertype of the original: they are unrelated types that cannot be cast between, which is exactly why the Java ...
What is subtyping? Subtyping is a key feature of object-oriented programming languages such as Java. In Java, Sis a subtype of T if S extends or implements T. Subtyping is transitive, meaning that if R is a subtype of S, then R is also a subtype of T (T is the super type of both Sand R).
As mentioned previously, generics can eliminate the requirement for casting.
I think that making Parent
a generic class is the way to go. You didn't explain what exactly is the purpose of the type T
in your example, but I suppose you want it to be the actual type of the entity, so for example your Parent
would inherit Entity<Parent>
.
You can still write polymorphic code in this scenario - you just have to use generics:
static void Foo<T>(Parent<T> p) where T : Parent<T>
{
Parent<T> entity = p.Find();
}
This method can be called with both ChildA
and ChildB
. The only tricky aspect is that you cannot actually create an instance of Parent<Parent<...>>
(because the dots would have to be replaced with more nested Parent<...>
types), but you can write somthing like this:
class ParentFix : Parent<ParentFix> { }
.. then you can pass instances of ParentFix
to the Foo
method as well.
I know this isn't the answer you're looking for, but I would recommend using a solid off-the-shelf ORM, like Entity Framework 4. It supports inheritance out of the box, and it's basic, fundamental usage is a repository.
I think you're in for a lot of pain if you try to roll this yourself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With