I am creating a .NET Framework MVC EF application for PC components. I wanted to make full use of inheritance, polymorphism and generic repository pattern - but was wondering if my initial design implementation is the best way to go about it.
The major sections of the codebase are below:
Repository
I wrote this intending for it to be a generic repository for each component to call to retrieve records from the db, but as you'll see in the controller class I end up declaring several repository instances anyway.
ComponentRepository.cs
public class ComponentsRepository<T> : IComponentRepository<T> where T : class, IComponent
{
private readonly ApplicationDbContext _context;
private DbSet<T> table = null;
public ComponentsRepository()
{
_context = new ApplicationDbContext();
table = _context.Set<T>();
}
public ComponentsRepository(ApplicationDbContext context)
{
_context = context;
table = context.Set<T>();
}
public void Delete(int id)
{
table.Remove(GetById(id));
}
public IEnumerable<T> GetAll()
{
return table;
}
public T GetById(int id)
{
return table.Find(id);
}
public void Insert(T component)
{
table.Add(component);
}
public void Save()
{
_context.SaveChanges();
}
public void Update(T component)
{
table.Attach(component);
_context.Entry(component).State = EntityState.Modified;
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Component Models
I require all components to have a shared parent class for grouping in lists, basket, etc. Each component has unique properties that act as the specifications. (e.g. Core clock)
Component.cs
public class Component : Interfaces.IComponent
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[DisplayName("Name")]
public string Name { get; set; }
[DisplayName("Description")]
public string Description { get; set; }
[DisplayName("Price")]
public decimal Price { get; set; }
public Manufacturer Manufacturer { get; set; }
[DisplayName("Component Type")]
public virtual ComponentType ComponentType => ComponentType.NoType;
public virtual string GetComponentTypeLink => "";
}
CPU.cs
public class CPU : Component
{
[DisplayName("Component Type")]
public override ComponentType ComponentType => ComponentType.CPU;
public override string GetComponentTypeLink => new UrlHelper(HttpContext.Current.Request.RequestContext).Action("CPU", "Products");
[DisplayName("Core Count")]
public int CoreCount { get; set; }
[DisplayName("Core Clock")]
public string CoreClock { get; set; }
}
Storage.cs
public class Storage : Component
{
[DisplayName("Component Type")]
public override ComponentType ComponentType => ComponentType.Storage;
public override string GetComponentTypeLink => new UrlHelper(HttpContext.Current.Request.RequestContext).Action("Storage", "Products");
[DisplayName("Size")]
public decimal Size { get; set; }
[DisplayName("Read Speed")]
public int ReadSpeed { get; set; }
[DisplayName("Write Speed")]
public int WriteSpeed { get; set; }
}
Controller
ComponentsController.cs
public class ComponentsController : Controller
{
private readonly IComponentRepository<CPU> _CPURepository;
private readonly IComponentRepository<Storage> _StorageRepository;
private readonly IComponentRepository<CPUCooler> _CPUCoolerRepository;
private readonly IComponentRepository<Memory> _MemoryRepository;
public ComponentsController()
{
_CPURepository = new ComponentsRepository<CPU>();
_StorageRepository = new ComponentsRepository<Storage>();
_CPUCoolerRepository = new ComponentsRepository<CPUCooler>();
_MemoryRepository = new ComponentsRepository<Memory>();
}
public ActionResult Index()
{
// Simulate list, basket, checkout, etc.
List<IComponent> componentList = new List<IComponent>();
componentList.AddRange(_CPURepository.GetAll());
componentList.AddRange(_StorageRepository.GetAll());
componentList.AddRange(_CPUCoolerRepository.GetAll());
componentList.AddRange(_MemoryRepository.GetAll());
return View(componentList);
}
public ActionResult Details()
{
// Select view based on component type to view each sub-class specification
return View();
}
}
Within the controller I'm creating a new repository instance for each concrete component implementation which gives of quite a bad smell. I don't know if this design would be elegant in handling CRUD functionalities down the line.
Any comments or insight would be greatly appreciated, thanks!