I am back trying to get into the .NET again, I have been of development for the past 10 years, though I started with .NET 1.0 and now it's a bit different. I was used to the N-tier model, with ADO.NET or what i liked even better was the recordSet in ASP. I am trying to get my head around this Repository pattern, Genneric pattern and the Entity Framework.
Please have patience with my knowledge as I have only been back for the past month. I am building a product / order service, just for fun, trying to de-couple it both to use as microservice and MVC or WinForms if I would like. I just want to learn the proper way of doing this.
The problem is that I do not get nested objects and I do understand this, maybe I need to properly join them together, but then again, why would I then use the EF if I don't get this for free? I understand you get all the modelling from the framework etc, but you get my point.
I have two models
Orders Model with the foreign key pointed out - which in my world would map automatically
public class Orders
{
[Key]
public int OrderId { get; set; }
public int ProductId { get; set; }
[ForeignKey("ProductId")]
public IEnumerable<Product> Product { get; set; }
public DateTime Datetime { get; set; }
}
Product Model
public class Product
{
[Key]
public int ProductId { get; set; }
public string ProductName { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public decimal Price { get; set; }
}
I have a Generic repository interface
public interface IGenericRepository <T> : IDisposable where T : class
{
IEnumerable<T> GetAllRecords();
IEnumerable<T> FindRecord(Expression<Func<T,bool>> predicate);
T GetRecordById(int objId);
void AddRecord(T obj);
void DeleteRecord(T obj);
void UpdateRecord(T obj);
}
I Implement this interface through
public class GenericRepository<T> : IGenericRepository<T>, IDisposable where T : class
{
private readonly DBContext _context;
private readonly DbSet<T> _DbSet;
public GenericRepository(DBContext context)
{
this._context = context;
this._DbSet = this._context.Set<T>();
}
public IEnumerable<T> GetAllRecords()
{
return _DbSet.ToList();
}
public IEnumerable<T> FindRecord(Expression<Func<T, bool>> predicate)
{
throw new NotImplementedException();
}
public T GetRecordById(int objId)
{
return _DbSet.Find(objId);
}
public void AddRecord(T obj)
{
_DbSet.Add(obj);
}
public void DeleteRecord(T obj)
{
_DbSet.Remove(obj);
}
public void UpdateRecord(T obj)
{
_DbSet.Attach(obj);
_context.Entry(obj).State = EntityState.Modified;
}
public void Save()
{
throw new NotImplementedException();
}
void IDisposable.Dispose()
{
throw new NotImplementedException();
}
}
And last i have the UnitOfWork with an interface that I implement through
public class UnitOfWork : IUnitOfWork
{
private DBContext _context;
// public ProductRepository productRepository { get; private set; }
//public OrderRepository OrderReposity { get; private set; }
public IGenericRepository<Product> productRepository { get; set; }
public IGenericRepository<Orders> OrderRepository { get; set; }
public UnitOfWork(DBContext context)
{
this._context = context;
this.productRepository = new GenericRepository<Product>(this._context);
this.OrderRepository = new GenericRepository<Orders>(this._context);
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
In the WebAPI controller I call the unitOfWork through
[Route("api/[controller]")] [ApiController]
public class OrdersController : ControllerBase
{
public readonly UnitOfWork UoW;
public OrdersController(IUnitOfWork _uow)
{
this.UoW = _uow as UnitOfWork;
}
And pointing to the API method GET / Orders
// GET: api/<OrdersController>
[HttpGet]
public IEnumerable<Orders> Get()
{
return UoW.OrderRepository.GetAllRecords();
}
It works like a charm, I think its a good way to implement this. I can easily create another application to use the back-end, I can mock and test this pretty well. Everything is in 4 different projects in the solution.
But the problem is the returns a null on the products objects. Feel free to give me all feedback you can, how I should build this if my solution is not preferred or if I am doing it too "de-coupled".
Thanks for a great forum and a great inspiration for learning
Best regards Martin