I have three general repository that handle three base classes:
public class Entity
{
public int Id { get; set; }
}
public class Repository
{
public TEntity[] GetAll<TEntity>() where TEntity : Entity
{
return _context.Set<TEntity>.ToArray();
}
}
public class ArchiveEntity : Entity
{
public bool Deleted { get; set; }
}
public class ArchiveRepository
{
public TEntity[] GetAll<TEntity>() where TEntity : ArchiveEntity
{
return _context.Set<TEntity>.Where(x => x.Deleted == false).ToArray();
}
}
public class LogicalStorageEntity : ArchiveEntity
{
public int StorageId { get; set; }
}
public class LogicalStorageRepository
{
public int CurrentStorageId { get; set; }
public TEntity[] GetAll<TEntity>() where TEntity : LogicalStorageEntity
{
return _context.Set<TEntity>
.Where(x => x.Deleted == false)
.Where(x => x.StorageId = CurrentStorageId)
.ToArray();
}
}
Is there way to have one repository that filters entities differently depending on base class? Something that looks like:
public class Entity
{
public int Id { get; set; }
}
public class ArchiveEntity : Entity
{
public bool Deleted { get; set; }
}
public class LogicalStorageEntity : ArchiveEntity
{
public int StorageId { get; set; }
}
public class UniversalRepository
{
public TEntity[] GetAll<TEntity>() where TEntity : Entity
{
if (typeof(TEntity) is LogicalStorageEntity)
{
return _context.Set<TEntity>
.Where(x => /* how to filter by x.Deleted */)
.Where(x => /* how to filter by x.StorageId */)
.ToArray();
}
if (typeof(TEntity) is ArchiveEntity)
{
return _context.Set<TEntity>
.Where(x => /* how to filter by x.Deleted */)
.ToArray();
}
return _context.Set<TEntity>.ToArray();
}
}
Edit. The quiestion is not about how to check if entity is of specific type. The real difficult part is to apply filter when you know that entity can be filtered by Deleted or some other property. Since there is limitation TEntity : Entity , you cannot access the Deleted property.
You can, but you shouldn’t.
The separate repository per entity type is the correct way to go because that way you encapsulate the entity specific logic in the repository for that entity. If you try and make a universal repository you will have to keep adding to/changing the logic in a huge method with loads of
ifchecks.If you want to try and promote some code re-use, you can however provide the functionality from a base repository and allow the specific repositories to specify the behaviour:
Using this approach, you can reduce the amount of repeated code but increase the readability and maintainability of the code base.