0

I have an architecture question. I have DAL project with poco classes (equivalent tables in database), BLL project and UI project. UI project has reference to BLL project and BLL project has reference to DAL project.

I would like to display in UI project data for example from table Product from database. Should I create in BLL project class the same like poco class in DAL project and return it to UI project and display it?

So this is mine poco class in DAL (equivalent table in database):

public class Product 
{

    public int  ID  {get; set; }
    public string  Name   {get; set; }
    public String  Address {get; set; }
}

In BLL I have created business object the same like poco class above:

public class ProductBO
{
    public int ID { get; set; }
    public string Name { get; set; }
    public String Address { get; set; }
}

In BLL I have also method which gets products from DAL and map them to business objects - ProductBO:

public class ProductService
{
    public List<ProductBO> GetAllProducts()
    {
        List<ProductBO> productsBO = new List<ProductBO>();

        using (var context = NorthwindFactory.CreateContext())
        {
            List<Product> products = context.Product.ToList();

            foreach (var product in products)
            {
                productsBO.Add(new ProductBO { ID = product.ID, Address = product.Address, Name = product.Name });
            }
        }

        return productsBO;
    }
}

And now in UI project in controller I call service from BLL which returns List and in view I can display data using business object ProductBO.

@model IEnumerable<WebApplication1.BLL.BusinessObjects.ProductBO>

<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Address)
        </th>
    </tr>
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Address)
        </td>
    </tr>
}
</table>

Is it correct architecture approach?

user3691221
  • 109
  • 2
  • 13
  • If it was me I would share the domain objects between the DAL and the BLL. This way you reduce the amount of duplicate code. For the views, if required I will create view models whish they interact with, but these view models also make use of the domain objects. This way you also don't need to convert between `Product` and `ProductBO` – 3dd Jun 18 '14 at 11:02

2 Answers2

1

Well, there is no single correct approach. But I tend to avoid creating set of DAL classes. Modern ORMs allow to work with POCO classes. Yes, there is some limitations (like enums) but IMHO it does not worth creating two copies of each business entity and mapping between them. So, I go with single POCO entity which sits in business logic assembly. Entity Framework works with that entity saves and loads it from database. No mapping.

Presentation layer is different. Usually you have several representations of same entity on different pages. You also would use different Data Annotation attributes to set restrictions on view models, or some UIHints. That would pollute your business entity with UI-specific logic. Also you will often need to display formatted or modified data, like FullName instead of FirstName and LastName of your Person entity. So, here I don't use my POCO business entities, and create view models instead.

With your product sample this approach will look like:

  • Business logic assembly has POCO entity Product
  • Persistence assembly references business logic assembly and uses same Product
  • UI project has different view models ProductViewModel, BriefProductViewModel etc. It's also responsible for mapping between Product and view models. Note - manual mapping is time-consuming. I suggest you to use some mapping library, like AutoMapper or ValueInjecter
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • Something must be wrong in your explanation. I suppose that your BL assembly references the "persistance assembly" to use it, and you also say that your persistance assembly references the BL to use the `Product`. That's a clear circular reference. How does VS handle it? (There must be some hidden ingredient: DI), project wuth interfaces?) I've seen that @Maarten's answer uses the same technique. I wonder how – JotaBe Jun 18 '14 at 13:43
  • +1 for mentioning that an additional "persistence" model is usually not worth the extra effort -- ORMs already kind of play that role. Additional layers of abstraction are always trade-offs between flexibility and complexity/cost. Also see this article : http://blog.ploeh.dk/2012/02/09/IsLayeringWorththeMapping/ – guillaume31 Jun 18 '14 at 14:44
  • 1
    @JotaBe "I suppose that your BL assembly references the persistance assembly" => why ? The BL shouldn't decide how or when its objects are persisted. It needs no knowledge of the persistence layer. – guillaume31 Jun 18 '14 at 14:44
  • @guillaume31. I try to understand how is that possible. For example, if you make an Order using the BL "Order.New(some data)", the business layer should store this somewhere, so it should call the Persisntence layer, so it should have a dependency to this layer. I understand the BL doesn't need to know how, but the BL decides when. How can the BL store data if it hasn't referenced the Persistence layer?. Unless these project defines interfaces, and uses DI to get the implementation of those interfaces, I don't know how it's possible. – JotaBe Jun 18 '14 at 14:53
  • "the business layer should store this somewhere" : no, the thing that calls the business layer should store this somewhere ;) It might be an (Application) Service, it might be the Controller (although some are against fat Controllers). – guillaume31 Jun 18 '14 at 14:56
  • 2
    @JotaBe as I said in answer, BL does not reference persistence assembly. It has entities and services AND definition of repository interfaces, which are implemented in persistence assembly. BL services define *when* to use repositories. Both assemblies are referenced by application - ASP.NET web site in this case. Implementation of repositories provided to BL services by main application. That's why BL does not know anything about persistence – Sergey Berezovskiy Jun 18 '14 at 16:10
  • I think that this answer can be absolutely confusing for the OP, who is using a classic 3-layer architecture and most probably has never implemented IoC. I think that adding the info on this comment, specially the part of *AND definition of repository interfaces*, and explaining that using IoC is required would make it much more useful for him. Once you have all the information, it's clear that you can implement DI and use the main app (web app) as the composition root to provide the implementation of interfaces required by the BL. Even having used DI this answer it's a bit confusing. – JotaBe Jun 19 '14 at 01:16
0

You should define you POCO (domain) objects in your BLL project, since they are business objects.

Your DAL should have a reference to the BLL, not the other way around.

Personally I am a follower of the Onion architecture which places your domain in the centre of your application. Any layer you add should only reference inward, not outward. So by that definition, your BLL is the centre, and is not referencing anything. Add a DAL layer, and it can only reference inwards, so it can reference the BLL. The UI layer is also only referencing the BLL, but not the DAL, since the DAL is an implementation detail.

Maarten
  • 22,527
  • 3
  • 47
  • 68
  • 1
    Why would DAL ever need need reference to BLL – RossBille Jun 18 '14 at 11:07
  • 1
    Maybe to use the POCO objects, to store them in a DB. – Maarten Jun 18 '14 at 11:08
  • in OPs example the POCO's are in the DAL – RossBille Jun 18 '14 at 11:13
  • So maybe as @3dd said - I should create new project with poco classes and DAL, BLL, UI projects should have references to project with poco classes? – user3691221 Jun 18 '14 at 11:50
  • My comment on the other answer also applies to this one. For someone who has probably never implemented IoC this must look like "black magic". – JotaBe Jun 19 '14 at 01:20
  • This answer is confusing. POCO are NOT defined in BL, they are defined in DAL, a DAL should never have a reference to BL. – mfs Aug 30 '20 at 20:37
  • @MuhammadFaraz I don't agree with that opinion. A BL defines business objects (=poco's), and services. A DAL is a provider of repo's that makes it possible to retrieve and store the business objects. My opinion is that the BL should not 'know' the DAL, but a DAL should know the BL. – Maarten Aug 31 '20 at 07:15