I have a basic design consisting of the following classes and interfaces:
a IRepository<TEntity> interface,
a Repository<TEntity> base class,
and a concrete TenantRepository class.
The "problem"
Since everything inherited by the interface has public access by definition, I am allowed to call the Add method (base class)
_tenantRepository.Add(new Tenant { Name = "blah" } );
while I should be calling the Create method on TenantRepository
_tenantRepository.Create("blah");
The question
It would be nice if I was able to define the Add method as protected so that client code could not access the method, but that's not allowed due to the simple fact that it's a method defined in the interface and must have public access.
Alternatively I could name the methods identical so that I actually override the implementation in the concrete class. That would prevent the client code from calling the Repository.Add directly. But in some cases I really want to prevent client code from calling the method defined in the base class.
Another alternative could be to write something like this:
new protected void Add(Tenant tenant)
{
}
but that makes me shiver (and it will break soon enough when I start refactoring method names).
Is there a better way to achieve this?
Some code snippets as reference:
The interface:
public interface IRepository<TEntity> : IDisposable where TEntity : IEntity
{
IQueryable<TEntity> GetAll();
void Delete(TEntity entity);
void Add(TEntity entity);
}
A small portion of the base class:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
protected IDbContext Context;
public Repository(IDbContext context)
{
Context = context;
}
public void Add(TEntity entity)
{
DbSet.Add(entity);
}
// Left out other, for this question irrelevant, method implementations
}
And finally the TenantRepository
public class TenantRepository : Repository<Tenant>
{
public TenantRepository(IDbContext context)
: base(context)
{
}
public Tenant Create(string tenantName)
{
var tenant = new Tenant
{
Name = tenantName,
Guid = Guid.NewGuid().ToString()
};
if (Exists(tenant.Name))
{
throw new TenantAlreadyExistsException(tenant.Name);
}
Add(tenant);
return tenant;
}
// Left out other, for this question irrelevant, method implementations
}
One solution would be to make TenantRepository not inherit from your Repository. After all, it sounds like they have different functionality (you want to have Create instead of Add.)
If you go this route, Repository becomes a private member of your TenenantRepository class, as only it would know what repository methods should be called when.
You could hide the Add method using explicit interface implementation. Basically, in Repository, do this:
public IRepository<Tenant>.Add(Tenant toAdd)
{
//do the add
}
This they can only get by casting to an IRepository.
if in a TenantRepository you need Add to check for uniqueness of the Tenant, you should include that logic within the Add method itself.
You should make Add in your base Repository class virtual and override it in your TenantRepository so that it performs the uniqueness check you now have in your Create method.
public interface IRepository<T>
{
void Add(T entity);
}
public class Repository<T> : IRepository<T>
{
// mocking Add so it works without a DB
public virtual void Add(T entity)
{
Console.WriteLine("{0} added", entity.ToString());
}
}
public class Tenant
{
public string Name{get; private set;}
public Tenant(string Name)
{
this.Name=Name;
}
public override string ToString() {return this.Name;}
}
public class TenantRepository : Repository<Tenant>
{
// Add is virtual, so it can be overridden by TenantRepository
public override void Add(Tenant entity)
{
// this represents your uniqueness check
if(entity.Name=="Paolo") throw new Exception();
base.Add(entity); // calling Add on the base Repository
}
//you can now avoid having Create or making it just call Add
public Tenant Create(Tenant entity)
{
this.Add(entity);
return entity;
}
}
Related
partial class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
}
My generic repository implements a common set of methods for TEntity like
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>()
}
which I can access like
Repository<User>().Get();
Many repositories does the same set of operation, so it is beneficial but now I want to extend Repository<User> to support some additional behavior.
partial class Repository<User> : IRepository<User>
{
public user DoMagicFunction()
{
}
}
so that I can use the repository like
Repository<User>().DoMagicFunction();
how can I extend the same generic class for Some Tentity to extend new behaviour instead of modifying it.
I could have done the same like creating another UserRepository to support new feature, but the accessor would become
UserRepository.DoMagicFunction();
but I want it to be like
Repository<User>().DoMagicFunction();
You can use an extension method:
public static class ExtensionMethods {
public static User DoMagicFunction(this Repository<User> repository) {
// some magic
return null; //or another user
}
}
This will thus add the function in a syntactically nice way to Repository<User> objects.
In case you want to support it not only for Users, but for subclasses of Users as well, you can make the function generic:
public static class ExtensionMethods {
public static TEntity DoMagicFunction<TEntity>(this Repository<TEntity> repository)
where TEntity : User {
// some magic
return null; //or another TEntity
}
}
C# has a language feature called Extension Methods, you probably are using them from the .NET framework without knowing (e.g. the linq extensions methods). It's common to extend your classes or even your interfaces with extension methods without breaking the functionality of your code. Here is an example for your case.
Suppose you have a generic IRepository interface:
public interface IRepository<TEntity> where TEntity : class, IEntity
{
IQueryable<TEntity> Entities { get; }
}
This interface adheres to the SOLID principles, especially the O and I principle.
Now suppose IEntity looks like this:
public interface IEntity
{
int Id { get; }
}
Now you could perfectly imagine an often reusable extension method like this:
public static class RepositoryExtensions
{
// similar to your MagicFunction
public static TEntity GetById<TEntity>(this IRepository<TEntity> repository, int id)
where TEntity : class, IEntity
{
return repository.Entities.Single(entity => entity.Id == id);
}
}
In a similar manner you could also extend your Repository class
public static class RepositoryExtensions
{
public static TEntity GenericMagicFunction<TEntity>(this Repository<TEntity> repository)
{
//do some stuff
}
}
You can now consume that like this:
var repository = new Repository<User>();
var user = repository.GenericMagicFunction();
You could also limit your extension method:
public static class RepositoryExtensions
{
public static User DoMagicFunction(this Repository<User> repository)
{
//do some stuff
}
}
But doing this will defeat it's purpose, you could rather just implement this in the Repository<User> class.
If your system and architecture uses Dependency Injection, you're probably injecting an IRepository<User> to your consuming classes. So the first or second extension method examples I've provided would make the most sense.
If you want to extend any repository you can do it like this.
public static class RepositoryExtension
{
public static void MagicMethod<TEntity>(this IRepository<TEntity> repo) where TEntity: class
{
....
}
}
For a specific repository (eg User repository) you can use a similar process
public static class RepositoryExtension
{
public static void MagicMethod(this IRepository<User> repo)
{
....
}
}
Extension methods are not the way to go, because the code that implements the method can only access public/internal members of the class they extend and you are likely to want your repository's DataContext to be private.
In my opinion, your approach needs to be changed slightly.
What if in the future you want to add a Delete method to your generic repository, but you have some entities that should never be deleted? You'll end up with an instance of a repository for something like PurchaseOrder that you'll either have to remember to never call delete on or you will have to create a descendant of Repository<T> that throws an InvalidOperationException if called. Both of which are poor implementations.
Instead, you should delete your IRepository<T> interface completely. Keep your Repository<T> class, but explicitly define a repository interface for every entity that only has the methods you require.
public class Repository<TKey, TEntity>......
{
public TEntity Get<TEntity>(TKey key)....
public void Delete(TEntity instance)....
...etc...
}
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
// Note: No delete is exposed
}
MyDependencyInjection.Register<IPurchaseOrderRepository, Repository<PurchaseOrder, int>>();
When you need additional methods on your repository you add them to your IPurchaseOrderRepository and create a descendant of Repository<T>
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
void DoSomethingElse(int orderNumber);
}
public class PurchaseOrderRepository: Repository<PurchaseOrder, int> {
public void DoSomethingElse(int orderNumber) {.......}
}
MyDependencyInjection.Register<IPurchaseOrderRepository, PurchaseOrderRepository>();
Extension method is a best choice for this case.
Note: I have not checked but you should check Dependency Injection still works well as normal.
You can use below code for testing:
public class Employee
{
}
public class User
{
}
public interface IRepo<TEntity> where TEntity : class
{
TEntity Get(int id);
DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate);
DbContext GetContext();
}
public class Repo<TEntity> : IRepo<TEntity> where TEntity : class
{
DbContext _context;
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>();
}
public DbContext GetContext()
{
return _context;
}
}
public static class RepoExtensions
{
public static ChangeTracker DoMagic(this Repo<User> userRepo)
{
return userRepo.GetContext().ChangeTracker;
}
}
public static class Test
{
public static void DoTest()
{
Repo<User> repoUser = new Repo<User>();
repoUser.DoMagic();
Repo<Employee> repoEmployee = new Repo<Employee>();
//repoEmployee.DoMagic();
}
}
this may be somewhere else under generic types but I cant seem to follow a lot of the answers. Apologies if this is a repeat of another question.
the following code is for a three layer app with Data, Logic and Presentation Layers
in my data layer I have a Collection of entitys and a base entity
public abstract class BaseEntity
{
int LastModifiedBy { get; set; }
DateTime LastModifiedDate{get;set;}
}
public partial class DocNum: BaseEntity
{
}
public partial class DataList: BaseEntity
{
}
in my logic layer I have a BaseDTO class for transferring data. here is the code for it
public abstract class BaseDTO
{
protected abstract void ConvertFromEntity(BaseEntity entity);
public abstract void ConvertToEntity();
}
I then go and create the implementation class DocNum based on it as follows
public class DTODocNum : BaseDTO
{
//properties here
public DTODocNum()
{
}
public DTODocNum(DocNum entity)
{
ConvertFromEntity(entity)
}
protected override void ConvertFromEntity(DocNum entity)
{
throw new NotImplementedException();
}
public override void ConvertToEntity()
{
throw new NotImplementedException();
}
}
however this will not compile telling me that no suitable method to override was found.
I know I can do the following but I want thhis method to only accept a DocNum entity from the Data Layer:
protected override void ConvertFromEntity(BaseEntity entity)
{
throw new NotImplementedException();
}
I have also tried generic types with the following
public abstract class BaseDTO
{
protected abstract void ConvertFromEntity<T>(T entity);
public abstract T ConvertToEntity<T>();
}
and the following in the derived class:
protected override void ConvertFromEntity<T>(T entity) where T:DocNum
{
throw new NotImplementedException();
}
but now the error given is Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly
Can any one help me implement this solution so that the DTODocNum can compile whilst referring to the entity type?
Move the type parameter to the class level and add a constraint:
public abstract class BaseDTO<T> where T : BaseEntity
{
protected abstract void ConvertFromEntity(T entity);
public abstract T ConvertToEntity();
}
public class DTODocNum : BaseDTO<DocNum> { ... }
I am just starting in DDD and have a question regarding interfaces of objects and repositories. Suppose I have the following objects
public interface IPerson { ... }
public class Student
{
double gpa;
...
}
public class Teacher
{
double salary; ...
}
then I also have two repositories such as
public class StudentRepository :IRepository { public void Save(Student) }
public class TeacherRepository :IRepository { public void Save(Teacher) }
My question is, suppose I have a list of IPerson objects called persons, is there a way where I can just do something like repository.Save(persons) ? Without having to use reflection to figure out what type the IPerson actually is.
I currently have another class
PersonRepository :IRepository
{
public void Save(IPerson person)
{
if(Person is Student)
{
new StudentRepository.Save(person as Student);
}
else if(Person is Teacher)
{ ....}
}
}
Then I can call personRepository.Save(persons);
However this doesnt feel like an optimal way to structure things. How can I improve this design?
Thanks
EDIT:
What I'm looking for is, say I receive an IPerson object called person. I do not necessarily know what implementation it is, I just want to call repository.Save(person) and have it call the correct repository. Is there a way to do this without using some sort of switch statement with reflection?
Consider using generic repository
class Repository<T> :IRepository<T>
{
public void Save(T entity)
{
...
}
}
Usage
IRepository<Student> repo1 = new Repository<Student>();
repo1.Save(new Student());
IRepository<Teacher> repo2 = new Repository<Teacher>();
repo2.Save(new Teacher());
Next you can use IoC container and DI just to pass repositories around instead of creating them
At the top level, say in the main method or global.asax
IRepository<Student> studentRepo = IoC.Current.Resolve<IRepository<Student>>();
Later in a class that needs to save data, pass IRepository<Student> studentRepo into constructor
class Foo
{
private IRepository<Student> repo
Foo(IRepository<Student> repo)
{
this.repo = repo;
}
public void Save(Student s)
{
repo.Save(s);
}
}
EDIT
You can move a save operation to the IPerson<T>
class Person<T> : IPerson<T>
{
private IRepository<T> repo;
Person(IRepository<T> repo)
{
this.repo = repo;
}
public void Save()
{
repo.Save<T>();
}
}
So when you derive Teacher and Student from Person<T> you pass correspondent T, like
class Student : Person<Student>
{
private IRepository<Student> repo;
Person(IRepository<Student> repo):base(repo)
{
...
}
}
This shall give you the ability to work with List without Reflection or switch kung fu.
You can potentially have a method with C# generics
interface Repository<TEntity> where TEntity : class {
void Save(TEntity entity);
}
But I would discourage having generic (as in generalized, not C# generics) repositories. Repository interface should be domain driven and specific to your entity. Please consider this article by Greg Young.
It is also not clear why you have interfaces for you entities (IPerson). Interfaces are usually created at the seam of the application. Are you planning to have more than one implementation of IPerson?
Two possible approaches.
First, interfaces specific for domain types
interface IStudentRepository
interface ITeacherRepository
class StudentRepository : IStudentRepository
class TeacherRepository : ITeacherRepository
Second, a generic interface
interface IRepository<T>
class StudentRepository : IRepository<Student>
class TeacherRepository : IRepository<Teacher>
I have a pretty straightforward generic repository:
public interface IRepository<TEntity, TNotFound>
where TEntity : EntityObject
where TNotFound : TEntity, new()
{
IList<TEntity> GetAll();
TEntity With(int id);
TEntity Persist(TEntity itemToPersist);
void Delete(TEntity itemToDelete);
}
I want to define a contract for a repository for the type Term without any special behaviour. So it looks like this:
public class TermNotFound : Term
{ public TermNotFound() : base(String.Empty, String.Empty) { } }
public interface ITermRepository : IRepository<Term, TermNotFound> { }
Now for testing, I want to create an in-memory implementation of the generic repo, so I have this (not finished for brevity):
public class InMemoryRepository<TEntity, TNotFound> : IRepository<TEntity, TNotFound>
where TEntity : EntityObject
where TNotFound : TEntity, new()
{
private IList<TEntity> _repo = new List<TEntity>();
public IList<TEntity> GetAll()
{
return this._repo;
}
public TEntity With(int id)
{
return this._repo.SingleOrDefault(i => i.Id == id) ?? new TNotFound();
}
public TEntity Persist(TEntity itemToPersist)
{
throw new NotImplementedException();
}
public void Delete(TEntity itemToDelete)
{
throw new NotImplementedException();
}
}
It's not hard to see how I want it to work. For my tests, I want the generic InMemoryRepository implementation to be injected to create my ITermRepository. How hard is that right?
Well, I can't get StructureMap to do it. I have tried using WithDefaultConventions and ConnectImplementationsToTypesClosing(typeof(IRepository<,>)) in the scanner without success.
Can someone please help me out?
Your InMemoryRepository doesn't implement ITermRepository interface. That's why you can't connect them.
The best thing you could do with what you have is injecting InMemoryRepository<Term, TermNotFound> for IRepository<Term, TermNotFound>.
If you really need to inject ITermRepository, then you'll need to have another repository class inheriting from InMemoryRepository and implementing ITermRepository:
public class InMemoryTermRepository
: InMemoryRepository<Term, TermNotFound>, ITermRepository
{
}
Now you can connect ITermRepository to InMemoryTermRepository using:
.For<ITermRepository>().Use<InMemoryTermRepository>()
If you have many interfaces like ITermRepository, you could create a StructureMap convention, to connect I...Repository to InMemory...Repository. The default convention is to connect IClass to Class.
public enum RepositoryType
{
ClinicRepository,
MedicationRepository,
PatientRepository,
TreatmentRepository
}
public class ObjectFactory<T>
{
public static IRepository<T> GetRepositoryInstance(RepositoryType type)
{
switch (type)
{
case RepositoryType.ClinicRepository:
return new what ?;
default:
return what ?
}
}
}
public interface IRepository<T>
{
void Add(T item);
void Remove(int id);
void Update(T item);
IList<T> GetAll();
T GetItemById(int id);
}
I'm trying to create a RepositoryFactory class and I copied what I've done so far. Could anyone please help me to figure this out ? I'm stuck !
Thanks in advance
edit :
I want something like this at the end. Is it possible to make 1 Repository class and implement something like
dc.THATOBJECT.insertonsubmit(item) ?
public class TreatmentRepository : IRepository<Treatment>
{
public void Add(Treatment item)
{
using (PatientsDataContext dc = new PatientsDataContext())
{
dc.Treatments.InsertOnSubmit(item);
dc.SubmitChanges();
}
}
The simplest of factories just requires that your types derived from IRepository have parameterless constructors.
public class ObjectFactory {
public static TRepository GetRepositoryInstance<T, TRepository>()
where TRepository : IRepository<T>, new() {
return new TRepository();
}
}
If you require specific constructors for a given repository type, you can specify the objects as an object array and create them using CreateInstance
public class ObjectFactory {
public static TRepository GetRepositoryInstance<T, TRepository>(
params object[] args)
where TRepository : IRepository<T> {
return (TRepository)Activator.CreateInstance(typeof(TRepository), args);
}
}
To use either of these, you just need to say
var treatmentRepo =
ObjectFactory.GetRepositoryInstance<Treatment, TreatmentRepository>();
To have something to return, you need to write a class that implements IRepository<T>.
public class SomeKindOfRepository<T> : IRepository<T>
{
public void Add(T item)
{
}
// and so on...
}
It appears there are four broad types (ClinicRepository, MedicationRepository, etc.) - are they very different in how they "store" things? If so, make a separate class for each one. Otherwise use the same class with some fields to control its behaviour.
Update
Based on your edits and comments, you have a repository that is really some operations on a table. The only thing that really varies is which table it wraps around. But the table is a member of a data context. So you could defer the choice of table to a derived class.
This would be the base class:
public class GeneralRepository<TEntity, TContext> : IRepository<TEntity>
{
protected abstract Table<TEntity> GetTable(TContext dc);
public void Add(Treatment item)
{
using (TContext dc = new TContext())
{
GetTable(dc).InsertOnSubmit(item);
dc.SubmitChanges();
}
}
// and so on for other methods
}
A derived class would only have to specify how to select a table from the context:
public class TreatmentsRepository : GeneralRepository<Treatment, PatientsDataContext>
{
protected override Table<Treatment> GetTable(PatientsDataContext dc)
{
return dc.Treatments;
}
}
You can do without the enum. You either need a generic repository type, or different repository types implementing IRepository<T>. If you use a generic repository, you can implement the factory by doing something along the lines of:
public class ObjectFactory<T>
{
public static IRepository<T> GetRepositoryInstance()
{
return new Repository<T>();
}
}
I would recommend that you use an Inversion of Control (IoC) container for this. In the Factory (or you could even go straight to the IoC container), could get the type.
public interface IClinicRepository : IRepository<Clinic> {}
public class ObjectFactory
{
public static IRepository<T> GetRepository(RepositoryType type)
{
switch (type)
{
case RepositoryType.ClinicRepository:
return container.Resolve<IClinicRepository>()
default:
throw new NotSupportedException()
}
}
}
or better yet Just use a generic method in your factory
public static IRepository<T> GetRepository<T>()
{
return container.Resolve<T>()
}
// to call it
var repository = ObjectFactory.GetRepository<IClinicRepository>();