In our code base we have a base model (PersistenceEntity
) that handles any models that are persisted to storage via a generic repository. This works well for fetching, adding and deleting. The area I want to improve is our update method to be encapsulated in the repository rather than fetching the object in the service layer, manipulating it (in whatever fashion the developer sees fit) and then saving it.
The repository update method should internally load the model, call the update method on the object and then save it (or call the AddOrUpdate extension).
To do this, I was thinking I could add an abstract method on the base class to enforce the developer to implement the update in the model rather than setting the properties in another layer.
public abstract T Update<T>(T existing) where T : PersistenceEntity;
So this would make the developer write a model that would like this:
public class MyClass : PersistenceEntity
{
public override MyClass Update<MyClass>(MyClass existing)
{
existing.SomeProperty = SomeProperty;
existing.SomeProperty2 = SomeProperty2;
return existing;
}
}
But when I implement it in this way, the compiler complains as the it thinks MyClass
is the name of T and not the concrete class. I think I'm missing something obvious here, but I just can't see it... Any suggestions would be appreciated.
You can avoid hiding a class by type parameter by making a PersistenceEntity
class generic itself
public abstract class PersistenceEntity<T> where T : PersistenceEntity<T>
{
public abstract T Update(T existing);
}
It means self-referencing generic constraint, because every class inheriting PersistenceEntity
should update an existing instance of itself type.
The implementation for MyClass
would be the following:
public class MyClass : PersistenceEntity<MyClass>
{
public override MyClass Update(MyClass existing)
{
existing.SomeProperty = SomeProperty;
existing.SomeProperty2 = SomeProperty2;
return existing;
}
}
Another option is to create an invariant interface, which incapsulates the Update
method (if you aren't allowed to make PersistenceEntity
class generic)
public interface IUpdate<T> where T : PersistenceEntity
{
T Update(T existing);
}
And then implement it
public class MyClass : PersistenceEntity, IUpdate<MyClass>
{
public MyClass Update(MyClass existing)
{
existing.SomeProperty = SomeProperty;
existing.SomeProperty2 = SomeProperty2;
return existing;
}
}