lundi 8 juillet 2019

Suitable design for EntityFramework and ASP .NET application structure

I'm currently trying to understand how to better structure my code for ASP .NET applications but I'm unclear as to which direction I should take. I was wondering if I could get some insight on what I have so far to see if I'm on the right path or I've completely missed the target.

From what I've gathered from my research:

  • The Repository pattern seems to be moot since EntityFramework already does it's own pseudo-implementation. The general consensus to just use EntityFramework directly rather than adding unnecessary abstractions unless you plan to use another framework other than EntityFramework.

  • Service layer/patterns utilize repositories in order to implement business logic and would probably be better than using repositories taking into consideration Entity Framework's structure.

I'm currently considering the following design but I'm not exactly sure whether this is suitable or good practice in the long run;

public class Manufacturer
{
  public int Id {get;set;}
  public string Name {get;set;}
  public string Description {get;set;}
  public string Address {get;set;}
  public string Phone {get;set;}
  public string Website {get;set;}
}

public class Asset
{
  public int Id {get;set;}
  public string Name {get;set;}
  public string Description {get;set;}
  public int ManufacturerId {get;set;}

  public virtual Manufacturer Manufacturer {get;set;}
}

// Generic Queries used within views for select lists and lookups.
public static class GenericManufacturerQueries
{
  public static List<Manufacturer> GetAll(InventoryDb context)
  {
    return context.Manufacturer.ToList();
  }

  public static List<Manufacturer> GetById(int id, InventoryDb context)
  {
    return context.Manufacturer.Where(x => x.Id == id).FirstOrDefault();
  }

  ...Omitted for brevity...
}

// Service class to facilitate Create/Update/Delete for each primary entity.
// Code could be too long for posting but the omitted sections also include
// creating/writing differences to a log of the sort. Hence, service classes
// also operate on auxiliary entities. 
public class AssetService
{
  private InventoryDbContext _context = null;

  public AssetService(InventoryDb context)
  {
    _context = context;
  }

  public void AddAsset(Asset model)
  {
    ...Omitted for brevity...
  }

  public void RemoveAsset(int assetId)
  {
    ...Omitted for brevity...
  }

  public void UpdateAsset(Asset model)
  {
    ...Omitted for brevity...
  }
}


Possible usage within a view model:

public class AssetCreateVM
{
  public int Id {get;set;}
  public string Name {get;set;}
  public string Description {get;set;}

  public ManufacturerId {get;set;}
  public List<SelectListItem> Manufacturers
  {
    get
    {
       using(var context = new InventoryDbContext())
       {
         return GenericModelQueries.GetAll(context).Select(x => new SelectListItem(){ Text = x.Name, Value = x.Id}).ToList();
       }
    }
  }

  public void SaveModel()
  {
    using(var context = new InventoryDbContext())
    {
      AssetService service = new AssetService(context);
      var model = new Asset()
      {
        Name = this.Name,
        Description = this.Description,
        ManufacturerId = this.ManufacturerId,
      };

      service.AddAsset(model);
    }
  }
}


In regards to the design, my thoughts at the time were the following:

  • I have entity classes within the data layer for each of my database tables. CRUD operation access are managed via EntityFramework's DbContext.

  • For generic queries I'm considering consolidating them within a single static/generic class that doesn't have to be instantiated as a way of avoiding re-writing code. In order to maintain a consistent/up-to-date transaction, I'm passing the context as an argument to each function within the classes.

  • With the services encapsulating the CRUD operations, I can potentially re-use the logic in other modules and areas of my applications other than my View Models.

  • I'm looking at possibly writing tests for the services by injecting in a mock context via the Entity Effort library but I'm unsure of how I'll be doing it at this stage.

Thanks for your time.

Aucun commentaire:

Enregistrer un commentaire