2

I'm trying to learn the N-Layer architecture and several other things, and I have a C# solution where I have the following layers:

  • Core/Infrastructure (Folder)
    • Core (Project)
      • Service interfaces
      • Domain models
      • Repository interfaces
  • Business Logic Layer (Folder)
    • Services (Project)
      • Different services
  • Data Access Layer (Folder)
    • DatabaseAccess (Project)
      • Entities generated via Entity Framework from existing database
      • Different repositories
  • Presentation Layer (Folder)
    • Shell (Project using Prism)
    • Different modules (Multiple projects acting as prism modules)

Does this setup seem correct?

It should pretty much mimic the following image: enter image description here

When structured like this, it seems very loosely coupled, however, an issue arises when I want to define a repository interface for an entity. The issue obviously being that I would have to reference the DAL project in order to use the entity in the interface... I can't figure out where I've gone wrong or what steps to take to correct this issue.

The generic repository interface in Core.Repositories:

public interface IRepository<TEntity> where TEntity : class
{
    TEntity GetByID(int ID);
    IList<TEntity> GetAll();
    IList<TEntity> Find(Expression<Func<TEntity, bool>> predicate);

    void Add(TEntity entity);
    void AddRange(IList<TEntity> entities);

    void Update(TEntity entity);

    void Remove(TEntity entity);
    void RemoveRange(IList<TEntity> entities);
}

An example repository interface where said issue would arise (Also in Core.Repositories):

interface IChildRepository : IRepository<ChildEntity> //In order to use ChildEntity I would have to add a reference to the DAL project
{
    IList<Child> GetAllChildren();
}

So in conclusion, should I not be using the repository pattern in this case, or what steps can I take to rectify the issue?

UPDATE:

A video I had seen about the repository pattern was somewhat incorrect and was the reason I had an error in my understanding of the pattern and an error in my code. I figured out what the issue was from finding a very nice blog post about the repository pattern.

I am creating specific repositories, but I'm using the generic repository as a helper, so that I don't need to repeat stuff like "GetAll", "Add", or "Find".

When defining my interface I should have done this:

interface IChildRepository
{
    IList<Child> GetAllChildren();
}

And then in my class:

class ChildRepository : Repository<ChildEntity>, IChildRepository
{
    IList<Child> IChildRepository.GetAllChildren() => GetAll().ToModels();
}

Obviously I need to repeat some code like "GetAllChildren", "GetAllParents", & etc. - I guess I'll just have to live with that.

  • why do you say 'folder' instead of project? – Ewan Aug 13 '17 at 19:34
  • Because it is a folder. First level are folders, second level are projects and third level are classes, etc. – Helios Aug 13 '17 at 19:44
5

Its correct. but your repositories should return business objects, not database 'entities'

Secondary point. Generic repositories are somewhat frowned upon. Its best to have specific repositories with methods that allow you to make full use of the database to retrieve the exact data you need.

Simplified diagram

  • Models and Interfaces (core) no dependencies
  • Repository, references Models
  • App (presentation layer?), references Models and Repository
  • Ah that was a mistake I made when writing the example, I actually do return business objects (I'll correct it). I do actually have specific repositories, but I use the generic repository to avoid duplicating code. Do you have another idea of how I might achieve that without my generic repository? – Helios Aug 13 '17 at 22:05
  • 3
    if you return business objects then what is the actual issue you are having? – Ewan Aug 13 '17 at 22:07
  • The issue was that I wanted to be able to define specific repositories and have them implement the generic repository so that I did not have to repeat code for all of them. I know now that I had an error in my understanding of the pattern (I watched a bad video about it). I have updated my main post with my "fix". – Helios Aug 16 '17 at 9:42
  • Sometimes DRY might lead you to build unecessary inheritances and/or compositions. KISS. Then, if you deem it necessary, refactor (DRY). I have been in favour of generics for many years. With the perspective of the time, I have to admit that the benefits rarely outweighted the costs (complexity). – Laiv Aug 16 '17 at 20:27

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.