开发者

Design question POCO objects / DAL access

开发者 https://www.devze.com 2023-01-24 09:36 出处:网络
i would like to implement the typical three layer architecture. My current approach looks as follows DAL - with EF 4.0 and repositories for each of my entities. access through interfaces

i would like to implement the typical three layer architecture. My current approach looks as follows

  • DAL - with EF 4.0 and repositories for each of my entities. access through interfaces
  • I was thinking of using POCO obje开发者_Go百科cts. My first question would be where should i put those files? In an assembly which is referenced by all other projects?
  • BLL - How do i get the data from the DAL to the BLL and then finally to the GUI Is it a good way if i would have a whole bunch of manager classes there like CustomerManager in the BLL. These classes would access the corresponding repository in the BLL and then pass the objects to the GUI

Or do you think it is better to put the repository in the BLL and access them directly from my say buttoneventhandler?

Hopefully you can bring some light into the darkness


We have the repos in the DAL. The BLL references the repositories via an interface - so the repositories are tied to the DAL but decoupled from the BLL. I don't know of any reason why the repositories couldn't be directly in the BLL. We've got them in the DAL as we don't put ANY logic in them. We then have "Managers" in the BLL which wrap the repositories and handle entity-specific logic.

FWIW we actually have a generic Repository(Of IEntity) and use unity to instantiate the appropriate repository as required - it's very compact and quite elegant. All our POCO entities implement IEntity which contains Id, CreatedDate, etc. which are common to ALL our entities. This gives some other benefits when you need to handle any type of entity generically - CreatedDate is set by the repository when CreateInstance() is called, ModifiedDate is set by the context itself when it commits an entity with a state of Modified

We keep entities in a separate project - The DAL needs to be able to reference them, as does the BLL. You don't want them in the DAL as swapping the DAL out would cause issues. You can't put them in the BLL or you get a circular reference. Configuration for the entities can live in the DAL as it's data source-specific.

We try to stick to the BLL taking in primitives and returning entities. Be careful about keeping entities in the UI for too long, especially in a web app as you may have a different context under the DAL by the time you return the entity to the BLL for processing (ie across requests stored in session or similar) this can result in all kinds of fun attaching/detaching entities from contexts and loses you some benefits like change tracking.

Hope that helps but if you want any clarification, let me know


This is our setup:

Company.Project.Domain.Model      (POCOs)
Company.Project.Business.Services (BLL)
Company.Project.Data.Repositories (Repository)
Company.Project.Web               (Presentation)
  • POCO's are in their own assembly. References nothing, and Referenced by all.
  • BLL execute queries against repositories, apply business rules and hydration. Returns ICollection<T> or T. References Repositories (via IRepository<T> generic interface) and POCOs.
  • Repository is set of generic classes implementing IRepository<T> to provide basic persistence against underlying store. Find, Add, Remove, etc. Returns IQueryable. References POCO's, Referenced by BLL.
  • Presentation is UI. References POCOs and BLL.

The end result is a like stack-like approach, and because basically everything is via interfaces (and DI registries), the flexibility is enormous.

We have Mock Repositories which get injected into the test projects via DI, and Entity Framework Repositories which get injected into the BLL via DI.

Example flow from UI -> DB:

// "Company.Project.Web.ProductsController.cs"
public class ProductsController : BaseController
{
   private IProductService _productService;

   public ProductsController(IProductService productService)
   {
      this._productService = productService; // DI makes me happy :)
   }

   public ActionResult GetOrdersForProduct(Product product)
   {
      var orders = _productService.GetOrders(product);
      return View(orders);
   }
}

// "Company.Project.Business.Services.ProductService.cs"
public class ProductService : IProductService
{
   private IRepository<Product> _productRepository;

   public ProductService (IRepository<Product> productRepository)
   {
      this._productRepository = productRepository; // DI makes me happy :)
   }

   public ICollection<Orders> GetOrdersForProduct(Product product)
   {
      return _productRepository
                .Find()
                .ForProduct(product) // IQueryable<Product> pipe/extension filter
                .ToList();
   }
}

// "Company.Project.Data.Repositories.GenericRepository.cs
public class GenericRepository<T> : IRepository<T> where T : class
{
   private IObjectSet<T> _objectSet;

   public GenericRepository(IUnitOfWork unitOfWork)
   {
      CurrentContext = unitOfWork as SqlServerUnitOfWork;
   }

   public IQueryable<T> Find()
   {
      return CurrentContext.GetEntitySet<T>();
   }

   protected SqlServerUnitOfWork CurrentContext { get; private set; }

   protected IObjectSet<T> CurrentEntitySet
   {
      // some plularization smarts in "SqlServerUnitofWork.cs", to dynamically pull
      // back entity set based on T.
      get { return _objectSet ?? (_objectSet = CurrentContext.GetEntitySet<T>()); }
   }
}

As you can see, i am a DI fanboy.


You can keep this really simple by keeping your repositories and POCOs in the same project. This would essentially be your Data Domain Model. Your POCOs are public and so are your repository interfaces. You should keep your concrete repositories internal to this project.

Your BLL could be a classic Facade or Service Locator. This project would massage your data and apply any relevant business rules before handing it over to the UI. This would also be responsible for validating data coming in from the UI before sending it over to the DAL.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号