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;
}
}
Related
I have N-Layer solution in .Net with PetaPoco as microORM. I get the entities generated from the template generator of PetaPoco. These entities T derive from the base class Record<T>. Then I extend them adding more data access facilities and custom Save() and Delete() methods that override the Record<T> default methods.
Following is the overrided Delete method from the entity (the method I want to call)
public partial class Document : Record<Document>
{
public new int Delete()
{
int rowsAffected;
using (var uow = DB.GetInstance().GetTransaction())
{
rowsAffected = base.Delete();
LogSystem("Deleting", "Deleting a document", 0, 0, GUID);
uow.Complete();
}
return rowsAffected;
}
}
Then when I create the generic repository the methods getting called are from the base class Record<T> and not my custom ones from the entities. When I call an entityRepository.Delete() method, the Delete() method from my entity should get called and not the one from the default Record<T> class.
The generic repository class is as follwos:
public abstract class GenericRepository<T> : IGenericRepository<T> where T : Record<T>, new()
{
public void Delete(T entity)
{
entity.Delete();
}
}
The cause of this problem is that in your GenericRepository you specify T as "something deriving from Record". So wenn calling entity.Delete(), this call will be linked to this base method, since this is only done once for all possible instances of T.
If you have access to the Record<T> class, just make the Delete() method virtual and override it in Document.
If not, try using something like this:
public class ExtendedRecord<T>: Record<T>
{
public virtual new int Delete()
{
base.Delete();
}
}
public partial class Document : ExtendedRecord<Document>
{
public override int Delete()
{
// ...
}
}
public abstract class GenericRepository<T> : IGenericRepository<T>
where T : ExtendedRecord<T>, new()
{
// ...
}
Confession: I have no knowledge of PetaPoco and its template generator.
The problem is more related to OO (specifically Inheritance) than PetaPoco IMHO. If generic repository is created with Record<T> which is also a base class for each entity, then what happening is as expected. You need to closely look into inheritance of your classes.
You may need to make few changes in the solution I am proposing below to match up with ORM functionality.
Solution 1:
Declare a new base class or interface something like below:
public interface IEntityBase{.....
Include the necessary members like Delete method in interface.
Then, derive each entity from this interface as well:
public partial class Document : Record<Document>, IEntityBase
Then, create a generic repository with this interface instead of Record<T> something like below:
public abstract class GenericRepository<T> : IGenericRepository<T> where T : IEntityBase
This way, you achieve your objective without changing much of your existing code.
Solution 2:
Another dirty solution is to cast the Record<T> to its actual instance.
public void Delete(T entity)
{
if(typeof(T) == typeof(Document))
Document myEntity = (Document)entity;
myEntity.Delete();
}
Casting in each method is definitely bad idea. Look for some better centralized location in your code. I just wanted to show you the way.
Solution 3:
Other thought is to make Delete method in Record<T> a virtual method. But I am not sure how your ORM works or even if your ORM allows this, so I will not comment on this.
I have an abstract super class and subclasses inheriting from it.
Each subclass MySubclass shall have a public static MySubclass CreateFrom(ISomething something) factory method. The interface of its argument is the same for all subclasses, but the return type must of course always be the type of the respective subclass.
Can I somehow achieve this to have static factory methods following an interface or abstract superclass method definition without creating a separate static factory class for each single subclass?
If the ISomething is always of the same (or at least a common) type, you could make the CreateFrom method of the superclass generic and Invoke the constructor of the inherited class with the parameter. Just make sure all your inherited classes have that constructor (Not sure but I don't think there is a way to 'force' a constructor pattern).
public abstract class SuperClass
{
public static T CreateFrom(ISomething something)
{
return (T)Activator.CreateInstance(typeof(T), something);
}
}
public class InheritedClass : SuperClass
{
public InheritedClass(ISomething something)
{}
}
This way you can create instances by calling
SuperClass.CreateFrom<InheritedClass>(something);
Or you split the creation and initialization:
public abstract class SuperClass
{
protected abstract void Initialize(ISomething something);
public static T CreateFrom(ISomething something) where T : new()
{
T result = new T();
T.Initialize(something);
}
}
public class InheritedClass : SuperClass
{
public InheritedClass()
{}
protected override Initialize(ISomething something)
{}
}
You can´t define static members on interfaces as static members belong to a certain class. However I can´t imagine of a reason to use this. You should ask yourself why you need such a functionality. Does a sub-class really have to instantiate itself or can the same easily be done with another independent (factory-)class?
Just create one simple factory-class with a generic parameter that indicates what to create.
class Factory<T> where T: new()
{
T CreateFrom(ISomething param)
{
return new T();
}
}
Now you can simply call it like this:
var myFactory = new Factory<MyClass>();
myFactory.CreateFrom(mySomething);
I resorted to a different solution in similiar kind of requirement. In my superclass which happened to be an abstract one I required to create an instance of subclass to do something with it so I did the following trick:
public abstract class Element
{
protected virtual void copyFrom(Element other)
{
}
protected abstract Elememt newInstanceOfMyType();
public object clone()
{
var instance= newInstanceOfMyType();
instance.copyFrom(this);
return instance;
}
}
Now all my subclasses inheriting from Element class required to override newInstanceOfMyType method to give away instance of its type and then also override copyFrom method to produce a perfect clone. Now people might argue that why an abstract Clone method cant do the same job? Yes it can. But I required cloned instance of subclass as well as an empty instance(without copying anything from current) so I came up with this architecture.
I have a class similar to the following:
public abstract class Manager<T, TInterface> : IManager<T> where TInterface : IRepository<T>
{
protected abstract TInterface Repository { get; }
public virtual List<T> GetAll()
{
return Repository.GetAll();
}
}
This works perfectly fine, however, is there a way to get away from having the TInterface in the abstract class declaration and in the resulting class that extends my generic abstract class:
public class TestManager : Manager<TestObject, ITestRepository>, ITestManager
I am forced to use ITestRepository and make the Repository property abstract due to the fact that it can contain custom methods that I need to know about and be able to call.
As I continue to build layers, I will have to keep doing this process the whole way up the stack. Examples would be if I had a generic abstract controller or service layer:
public class TestService : Service<TestObject, ITestManager>, ITestService
Is there a better way to do this or is this the best practice to allow a generic class to call another generic class?
It seems that all you want to do is to make Manager<T> testable, and use a mock as a repository that you can query for special members.
If that's the case, maybe you can change your design to this:
public class Manager<T> : IManager<T> {
protected IRepository<T> Repository { get; set; }
// ...
public virtual List<T> GetAll() {
return Repository.GetAll();
}
}
Now, all the specifics of testing are in a testing subclass:
public class TestingManager<T> : Manager<T> {
public new ITestRepository<T> Repository {
get {
return (ITestRepository<T>)base.Repository;
}
set {
base.Repository = value;
}
}
}
When you write your unit tests, you create TestingManager<T> instances (referenced through TestingManager<T> declared variables and fields), and you provide them with a test repository. Whenever you query their Repository, you'll always get a strongly-typed test repository.
UPDATE:
There's another way to solve this, without a subclass. You declare your repository objects as test repositories that you pass to Manager<T>s and you query them directly, without going through the Manager<T>.
[Test]
public void GetAll_Should_Call_GetAll_On_Repository_Test() {
var testRepository = new TestRepository();
var orderManager = new Manager<Order>(testRepository);
// test an orderManager method
orderManager.GetAll();
// use testRepository to verify (sense) that the orderManager method worked
Assert.IsTrue(testRepository.GetAllCalled);
}
No, you can't get around it. You can try, but the result will be ugly and in some way incorrect. The reason is that you are asking generics not to be generic but still be generic.
If a new class uses a generic class, either in inheritance or composition, and it itself does not know enough to specify the type parameters to the generic class it is using, then it must itself be generic. It is analogous the method call chains, where a method may pass parameters along to another method. It can't make up the arguments to the inner method, but must rather take them as parameters itself from a caller that does know what they are. Type parameters are the same.
One thing that does make this feel like code smell is the fact that you can't have a variable of type Manager<,>. It has to be fully type-specified. One solution I've come up with is to have non-generic interfaces that the generic classes implement. These interfaces have as much of the public interface of the generic class as is possible (they can't have methods or properties that reference the type parameters). Then you can pass around variables of the type of the interface and not have to specify type parameters.
Example:
interface IExample {
string Name { get; }
void SomeNonGenericMethod(int i);
}
class Example<T> : IExample {
public string Name { get { ... } }
public void SomeNonGenericMethod(int i) {
...
}
public T SomeGenericMethod() {
...
}
}
TL;DR:
Is there some way to add an abstract method to a base class that allows derived classes to override the method's return type, without the use of generics, and without the use of the new keyword?
I'm working on developing some custom templates for LLBLGen Pro. In the process, I refuse to change the default templates that LLBLGen Pro offers, so that my approach doesn't overwrite other peoples' files if they choose to implement my templates.
One task I've started working on (and made good headway toward) is developing a template that generates a DTO for each entity. Along those lines, one objective is to provide my entities with a ToDTO() method. In the interest of generic programming, I've decided to define this method within a common base class, and this is where my trouble starts.
Keep in mind that the purpose of defining the ToDTO() method in the base class is because I'm looking to create a generic repository (with a Fetch() method, for example) that I'd like to have work off the CommonEntityBase, as opposed to a specific entity.
LLBLGen defines its CommonEntityBase class like so:
public abstract partial class CommonEntityBase : EntityBase2 {
// LLBLGen-generated code
}
My original plan was to add my method to another partial class like so:
public abstract partial class CommonEntityBase {
public abstract CommonDTOBase ToDto();
}
I thought that the inherited classes would be able to define the return type in their methods as a type derived from the base class's return type, like so:
public partial class PersonEntity : CommonEntityBase {
public override PersonDTO ToDto(){ return new PersonDTO(); }
}
but I was wrong.
My second attempt was to define the class using generics, as such:
public abstract partial class CommonEntityBase<T> : CommonEntityBase
where T : CommonDTOBase {
public abstract T ToDto();
}
Simple enough. All I'd have to do is have my generated entity classes inherit from this new entity base. Just one caveat. As I don't want to overwrite LLBLGen's templates, it's back to partial classes.
LLBLGen's individual entities have this definition:
public partial class PersonEntity : CommonEntityBase {
// LLBLGen-generated code
}
And herein lies my problem. In order for my method to work, I would have to create my own partial class with this definition:
public partial class PersonEntity : CommonEntityBase<PersonDTO> {
public override PersonDTO ToDto(){ return new PersonDTO(); }
}
Of course, this isn't possible, because, as I now know,
All of the parts [of a partial class] that specify a base class must agree, but parts that omit a base class still inherit the base type.
The third thing I was going to attempt was simply overriding the base class's function definition with the new keyword:
public abstract partial class CommonEntityBase {
public virtual CommonDTOBase ToDto(){ return null; }
}
public partial class PersonEntity : CommonEntityBase {
public new PersonDTO ToDto(){ return new PersonDTO(); }
}
However, this defeats the purpose of my approach completely, as I want to be able to access PersonEntity's ToDTO() method when it's cast as a CommonEntityBase. With this approach, doing:
CommonEntityBase e = new PersonEntity();
var dto = e.ToDto();
would result in dto being null, which I don't want.
I've come across various links discussing my first approach, and why it won't work, and typically pointing to my generic approach as a solution in the general sense. However, in my situation, generics do not appear to work.
All this to ask whether or not what I'm trying to accomplish is possible.
Is there some way to add an abstract method to a base class that allows derived classes to override the method's return type, without the use of generics, and without the use of the new keyword?
Or perhaps I'm approaching this from the wrong angle, and there's some other technique that could solve my problems?
EDIT
Here's a use-case for what I'd like to accomplish with the entities, taking Porges's approach:
public class BaseRepository<D,E> where D : CommonDTOBase where E : CommonEntityBase,new
public D Get(Guid id){
var entity = new E();
entity.SetId(id);
// LLBLGen adapter method; populates the entity with results from the database
FetchEntity(entity);
// Fails, as entity.ToDto() returns CommonDTOBase, not derived type D
return entity.ToDto();
}
}
Instead of:
public abstract partial class CommonEntityBase {
public abstract CommonDTOBase ToDto();
}
public partial class PersonEntity : CommonEntityBase {
public override PersonDTO ToDto(){ return new PersonDTO(); }
}
Why are you not just returning a DTO like this:
public abstract partial class CommonEntityBase {
public abstract CommonDTOBase ToDto();
}
public partial class PersonEntity : CommonEntityBase {
// changed PersonDTO to CommonDTOBase
public override CommonDTOBase ToDto(){ return new PersonDTO(); }
}
I think that's more idiomatic for OO code. Is there a reason you need to know the exact type of the DTO?
I don't know LLBLGen, but I believe you could solve your problem this way, by introducing an interface to hold the type parameter:
public interface DTOProvider<T> where T : CommonDTOBase {
public T ToDTO();
}
And then for your entity classes, do this:
public partial class PersonEntity : CommonEntityBase, DTOProvider<PersonDTO> {
public PersonDTO ToDto() { return new PersonDTO(); }
}
Because partial classes can introduce different interfaces, this works. The only sadness is that a cast is required to get access to the method via the base type:
public void DoSomethingWithDTO<T>(CommonBaseEntity entity)
where T : CommonDTOBase {
T dto = ((DTOProvider<T>) entity).ToDTO();
...
}
Of course, you can call ToDTO directly without the cast when you have a reference of one of the entity derived types:
public void DoSomethingWithPersonDTO(PersonEntity entity)
{
PersonDTO dto = entity.ToDTO();
...
}
If you are using .NET Framework 4, you can use generic variance to make the DTOProvider interface easier to use from code that just cares about working with CommonDTOBase by declaring the DTO type covariant:
public interface DTOProvider<out T> where T : CommonDTOBase {
public T ToDTO();
}
(Notice the 'out'.) Then your DoSomethingWithDTO method doesn't need the type parameter:
public void DoSomethingWithDTO(CommonBaseEntity entity) {
CommonDTOBase dto = ((DTOProvider<CommonDTOBase>) entity).ToDTO();
...
}
It is tempting to try and declare : CommonBaseEntity, DTOProvider<T> on the CommonBaseEntity partial class. Unfortunately that doesn't work, because when the partial definitions are merged the type parameter is carried over and your CommonBaseEntity type ends up being a generic type, which it looks like is what got you into a bind in the first place.
I have the following classes (trimmed to only show the basic structure):
public abstract class BaseModel {
public bool PersistChanges() {
// Context is of type "ObjectContext"
DatabaseHelper.Context.SafelyPersistChanges(this);
}
}
public static class ObjectContextExtensions {
public static bool SafelyPersistChanges<T>(this ObjectContext oc, T obj) {
// Persist the object using a transaction
}
}
[Persistent("LEADS")]
public class Lead : BaseModel {
// Extra properties
}
public class LeadsController : Controller {
public ActionResult Save(Lead lead) {
lead.PersistChanges()
}
}
My Lead class derives from BaseModel, which contains a method to persist the object's changes to the database using a transaction. I implemented the transactional persist with an extension method. The problem is that by passing this to SafelyPersistChanges in my BaseModel class, the generic T on the extension method is set to BaseModel. However, since BaseModel isn't marked as a persistent object (which it cannot be), the ORM framework throws an exception.
Example:
Lead lead = LeadRepository.FindByNumber(2);
lead.SalesmanNumber = 4;
// Calls "ObjectContextExtensions.SafelyPersistChanges<BaseModel>(BaseModel obj)"
// instead of "ObjectContextExtensions.SafelyPersistChanges<Lead>(Lead obj)"
lead.PersistChanges();
The above block raises the following exception:
Cannot create mapping for type 'SalesWeb.Data.BaseModel' without persistent attribute.
Any ideas?
Extension Methods are statically bound at compile time. At the point in which SafelyPersistChanges is called, this is typed as BaseModel and hence your exception. In order to get the behavior you want, you'll either need to do an ugly if statement with lots of casting or force the call to the derived class.
Make PersistChanges an abstract method. Then implement the call in the derived classes with exactly the same code.
public class Lead {
public override bool PersistChanges() {
// Context is of type "ObjectContext"
DatabaseHelper.Context.SafelyPersistChanges(this);
}
}
Now this will properly be Lead
I would have designed this differently, making "public bool PersistChanges()" call a virtual method, that is overridden in each subclass.
So, you want a "single" implementation, that varies against a type known by the caller. Sounds like a job for Generics.
public static bool PersistChanges<T>(this T source)
where T : BaseModel
{
// Context is of type "ObjectContext"
//static property which holds a Context instance is dangerous.
DatabaseHelper.Context.SafelyPersistChanges<T>(source);
}
You could solve this using the curiously recurring template pattern:
// change your code to this
public abstract class BaseModel<TDerived> where TDerived : BaseModel
{
public bool PersistChanges() {
// Context is of type "ObjectContext"
DatabaseHelper.Context.SafelyPersistChanges((TDerived)this);
// ^
// note the cast here: -----------------------|
}
}
public class Lead : BaseModel<Lead> { }
// the rest of your code is unchanged
That would work, but I'd probably just follow the other suggestions and use a virtual method.