lundi 11 décembre 2017

My Application layers are overalapping and not designed correctly

I've been trying to put together a tiered app but it feel very clunky. All the examples and tutorials I've seen are extremely basic and don't seem to hold up when applied to my project.

Issue 1) I believe I have the DAL how I want it but the BLL and API layers require me to pass the datacontext all the way down from the UI when it shouldn't reference the data layer.

Issue 2) I have 2 base classes for all my data models, BaseModel and BaseNameModel. I don't want to have to create a specific Repo for every single DB object and implement the exact same Search() method over and over. So I tried to use a generic one and only create specific ones when I need to override. This forced me to move my Search method to a new API layer and remember which entities I had to create specific implementations for.

I know the overall design is backwards but I can't figure out why.

*** Model layer ***

// Base class for all DB Models
public class BaseModel
{
    int Id {get; set;}
}

// 95% of DB Models have this property
public class BaseNameModel
{
    int Id {get; set;}
    string Name {get; set;}
}

*** DAL ***

// Context Interface
public interface IDataContext
{
    T GetById<T>(int Id, params string[] joins) where T : BaseModel;
    IQueryable<T> Get<T>(params string[] joins) where T : BaseModel;
    IQueryable<T> Get<T>(Expression<Func<T, bool>> where = null, params string[] joins) where T : BaseModel;
}

// Entity Framework Context
public class EFContext : DbContext, IDataContext
{
    public EFContext() : base()
    {
        Database.SetInitializer<EFContext>(null);
    }

    public DbSet<User> Users { get; set; }
    public DbSet<School> Schools { get; set; }

    T GetById<T>(int Id, params string[] joins) where T : BaseModel
    {
        var rv = Set<T>().Where(where);
    }

    IQueryable<T> Get<T>(params string[] joins) where T : BaseModel
    {
        var rv = Set<T>();
        foreach (string join in joins)
            rv.Include(join);
    }

    IQueryable<T> Get<T>(Expression<Func<T, bool>> where = null, params string[] joins) where T : BaseModel
    {
        var rv = Set<T>().Where(where);
        foreach (string join in joins)
            rv.Include(join);
    }
}

// Mock Context
public class MockContext : IDataContext
{
    T GetById<T>(int Id, params string[] joins) where T : BaseModel
    {
        // Return IList<T>.Where(m => m.id == Id);
    }

    IQueryable<T> Get<T>(params string[] joins) where T : BaseModel
    {
        // Return IList<T>;
    }

    IQueryable<T> Get<T>(Expression<Func<T, bool>> where = null, params string[] joins) where T : BaseModel
    {
        // Return IList<T>.Where(where);
    }
}

*** BLL ***

// BLL Repo using IDataContext
public class Repo<T>
{
    private IDataContext _context;
    public Repo(IDataContext dataContext)
    {
        _context = dataContext;
    }

    public IQueryable<T> Get(params string[] joins)
    {
        return _context.Get<T>(joins);
    }
}

*** API layer ***

// Generic API-ish layer
public class GenericAPI<T> where T : BaseNameModel
{
    Repo<T> repo = new Repo<T>
    public virutal BaseSearchResult Search(BaseSearchCriteria searchModel)
    {
        return repo.Get(e => e.Name == searchModel.Name);
        // convert results to BaseSearchResult and return
    }
}

// Entity Specific API-ish layer
public class UserApi : GenericAPI<User>
{
    public virutal UserSearchResult Search(UserSearchCriteria searchModel)
    {
        return repo.Get(e => e.Name == searchModel.Name && e.Grade == searchModel.Grade);
        // convert results to UserSearchResult and return
    }
}

Aucun commentaire:

Enregistrer un commentaire