Randolph Cabral’s Weblog

…beauty is just a dimmer switch away…

Exploring N-Tier Architecture with LINQ to SQL (Part 3 of n)

Posted by Randolph Cabral on Thursday, May 8, 2008

Part 3 – Creating Business Entities from Data Entities

In part one of this series we looked at how LINQ to SQL entities are structured by analyzing its members and mappings.  We concluded that that they aren’t suitable in a model where we would derive from them because doing so would hide the LINQ to SQL mappings from the query provider.  Creating a translation layer to handle loading and tracking of business entites would be too monumental a task to take on.   Clearly that’s not an option either.  Ideally, we want to encapsulate the data entities in business entities without sacrificing code re-usability.  Fortunately, we have a neat pattern that we can use to do just that and it’s called object composition.

Do the names Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides ring a bell?  Do you know what I’m referring to when I say, “GoF”?  Yes, you guessed it.  The Gang of Four and their book, Design Patterns: Elements of Reusable Object-Oriented Software.  In the book, they cite several important design techniques such as programming to an interface and object composition.  The one we’re interested in right now is object composition.  Take for example a business requirement where every customer record must have address data for billing and shipping.  Because the requirements for the Customer object only require a couple of addresses we can model the relationship with object composition using an Address class.  The code sample below illustrates how we would write the Customer class using this pattern.  Notice that there are two public Address properties which represent billing and shipping data as separate object instances.

public class Address

{

  public string Street { get; set; }

  public string City { get; set; }

  public string PostalCode { get; set; }

}

 

public class Customer

{

  public Address BillingAddress { get; set; }

  public Address ShippingAddress { get; set; }

}

With a little tweaking, we should be able to apply this pattern to reuse the LINQ to SQL entities within our business classes.  In the following code sample, we start by writing a business layer customer class called CustomerBus with an internal constructor that accepts a LINQ to SQL entity reference.  A private member that composes the LINQ to SQL Customer class keeps the reference in a safe place.  Now here’s where we deviate a little from the composition pattern.  Rather than adding a public property to expose the LINQ to SQL class, we’ll add public properties that expose each of the LINQ to SQL entity properties instead.  Doing this gives us more granular control in dealing with the data entity properties.  For example, we can change the names of the exposed properties, hide certain properties, and create custom domain specific validation logic for those properties we choose to expose.

//Business class

public class CustomerBus

{

  //Internal constructor that accepts LINQ entity reference.

  internal CustomerBus(Customer linqEntity)

  {

    LinqEntity = linqEntity;

  }

 

  //Private LINQ entity reference

  private Customer LinqEntity { get; set; }

 

  //Sample property that exposes a LINQ entity property

  public string CustomerID

  {

    get

    {

      //Expose the LINQ entity property

      return LinqEntity.CustomerID;

    }

    set

    {

      //Add domain specific validation logic here if desired.

      LinqEntity.CustomerID = value;

    }

  }

 

  …

}

 

Associations

Let’s take a look at how we would create relationships using this model.  One advantage of keeping a reference to the LINQ to SQL entity is that we have access to the relationships in the data layer.  Remember, our business entities can be constructed with the LINQ to SQL entities passed in as an argument to the internal constructor.  We can use the existing relationships created by LINQ to SQL in the data layer for free.  Our job just got a lot easier because all we need to worry about now is promoting the LINQ to SQL entity to a business entity.  Subsequently, we’re going to need to expose the LINQ to SQL entity member by declaring the property as “internal”.  This exposes the member to the other business entities in the assembly safely.  We’ll need this so we can read the LINQ to SQL entity to customize the add and remove logic in our collections.

//Business class

public class CustomerBus

{

 

  //Changed from private to internal.

  //And added custom getter and setter

  //LINQ entity reference

  private Customer _linqEntity = null;

  internal Customer LinqEntity

  {

    get

    {

      if(_linqEntity == null)

        _linqEntity = new Customer();

 

      return _linqEntity;

    }

    set

    {

      _linqEntity = value;

    }

  }

 

  …

Simply exposing the EntitySet<T> member from the data layer is not desirable in this case because that would expose the LINQ to SQL entities.  Support for customized add and remove logic to handle the EntitySet<T> reference requires a specialized collection class.  Our new collection class derives from System.Collections.ObjectModel.Collection<T> which implements many of the behaviors we need to manage the contained entities.  By deriving from Collection<T>, we get all of its functionality for free.  Next we can create a custom constructor that accepts the EntitySet<T> reference and declare it internal to the assembly.  We want to do this so that new collections of this type can only be instantiated from within this assembly to ensure that all instantiated objects are connected to a context.  The constructor will be responsible for promoting the LINQ to SQL entities to business entities and adding them to the collection.  Next we can add the specialized add and remove methods that hide the base class implementations to support management of the EntitySet<T> reference.  Now adds and removes are tracked by a context and can be processed as a batch.  Cool!

//Specialized business collection for OrderBus class

public class OrderBusCollection : Collection<OrderBus>

{

  //Internal constructor that uses the EntitySet<T> to hydrate itself

  internal OrderBusCollection(EntitySet<Order> entitySet)

  {

    EntitySet = entitySet;

    foreach (var linqEntity in EntitySet)

    {

      var entity = new OrderBus(linqEntity);

      base.Add(entity);

    }

  }

 

  private EntitySet<Order> EntitySet { get; set; }

 

  public new void Add(OrderBus entity)

  {

    EntitySet.Add(entity.LinqEntity);

    base.Add(entity);

  }

 

  public new void Remove(OrderBus entity)

  {

    EntitySet.Remove(entity.LinqEntity);

    base.Remove(entity);

  }

 

  public new void RemoveAt(int index)

  {

    Remove(this[index]);

  }

}

At this point, we can add the custom collection members to the business class as seen in the following code sample.  The custom “lazy” getter implementation ensures that we load the collection once it is requested and keeps a reference to the instance for future reference.  Now we have a working model that deals with the LINQ to SQL entities behind the scenes allowing for presentation code to interact purely with business entities.  Additionally, we can implement business-specific logic in the business classes in the form of validations or custom behaviors.

//Business class

public class CustomerBus

{

  //Association to orders

  public virtual OrderBusCollection Orders

  {

    get

    {

      if (_Orders == null)

        _Orders = new OrderBusCollection(LinqEntity.Orders);

 

      return _Orders;

    }

  }

  private OrderBusCollection _Orders = null;

 

  …

Yes, I know it’s lot of code to have to write by hand.  But this is one of those busy tasks that can clearly be remedied with a custom code generator.  I’m currently working on one that I will make available in a future post.  Until then, there will be a lot of code to write.  The result of writing the code is clear.  We’ve created a business entity layer that abstracts the data entities away and gives us a nice place to add domain logic.  Another point of consternation might be with the pervasive use of the LINQ to SQL entities in the business layer.  This is one case where I feel the benefit of having those entity references localized in each business class outweigh the challenges that might be introduced with changes in the data tier.  We can somewhat isolate those issues with a custom code generator which should take most of the pains away.  The code generator I’m working on declares each business class as a partial class.  This will allow us to keep our custom implementation separate from anything that was automatically generated by the code generator.

In the next post, we’ll revisit the BusinessContext class to give it functionality to attach newly constructed business objects.  We’ll also take a look at the result of our efforts so far with a sample web application that uses our new business layer and take a peek at SQL Profiler to check out how our changes impact LINQ to SQL’s query provider.

About these ads

6 Responses to “Exploring N-Tier Architecture with LINQ to SQL (Part 3 of n)”

  1. […] Exploring N-Tier Architecture with LINQ to SQL (Part 3 of n) […]

  2. Jon Kruger said

    In your opinion, why would you create business objects that are essentially the same thing as your data objects? If you’re using a code generator, the business objects and data objects are pretty much going to look the same. If you did make any changes between the business model and the data model, I would think that writing LINQ queries against the objects would be confusing because you would have to figure out which objects you would query against.

    I know that a lot of purists don’t agree with me on this one, but I don’t favor creating separate business objects from data objects. Sure, it’s somewhat annoying in some cases that my objects look exactly like the database tables (especially when dealing with many-to-many relationships), but is it worth all the time, effort, and code to create a separate set of business objects just to alleviate this pain? People might argue that creating a separate set of business objects will insulate the rest of the app from database refactoring, but if you refactored your database so that the business model and data model are drastically different, you are going to have all kinds of problems writing and optimizing queries.

    In the end, I have a job to do and I have to get that job done on time. So I have to balance the “purity” of my code with what will help me get the job done on time.

    Just my $.02. It sounds like the Entity Framework will fix a lot of these problems anyway. :)

    Jon

  3. Randolph Cabral said

    @Jon,

    Firstly, thanks for your $.02. I think your views are shared by a vast silent underground community of developers and I’m honored to try and offer an explanation from my personal experiences. So here it goes.

    The first point I want to make is about separation of data entities from business entities. I agree that there are times when using the data entities directly makes sense. Especially if your data entities closely match your domain model. One very important requirement I would consider a deal-breaker is if the data entities can be extended with behaviors. Additionally, I prefer using partial class definitions to add behaviors. Happily, LINQ to SQL entities are declared partial for this very purpose.

    Okay, so what about when the data entities don’t match the domain model at all? In this case, I would recommend writing business entities to represent the domain. More than having relationships conveniently available from each entity, the ultimate goal is to build out behaviors. This is the spirit behind all of the extra effort to build business entities. I’ve found that a really well designed domain model can double as a way of confirming feature requirements because the code becomes easily legible even by domain experts and stakeholders. The benefits of insulation from database refactoring is not necessarily a strong argument for business entities. Let’s face it, when the database changes it’s typically a significant change that requires modifications to all tiers of the application.

    The second point I want to make is about “purity” of code. I interpret your comments as more of a call to pragmatism as opposed to challenging “purity”. I’ve often found myself at this junction weighing architecture versus time lines. The key to answering this concern is to dissect what we really mean when we use words like “purity” and “purists”. I like to equate it to academia. Technically, the academic way works and is proven with a lot of literary works proclaiming its superiority. However in practice, it may not always be the most practical or efficient solution. I guess what I’m really trying to say here is to do what makes best sense for your project. The last thing you want to do is to bloat the amount of work you really need to do to get the job done. Building a simple data collection system may not warrant a fully built-out domain layer. More complicated financial systems or business intelligence systems, I would argue, definitely warrant a complete domain model with behaviors.

    -Randy

    • Timex said

      Randolph, your blog went dead, so I’ll try to wake it! Wakey Wakey!

      Nice write-up and I definitely agree with you, generally speaking. Perhaps it needs to be articulated that you are showing how to use an ORM in a layered/distributed architecture; that’s a very important point perhaps overlooked. Now that is to say that one does not HAVE to have a dedicated business layer per se, but if they did, your approach is a pretty good guide, I’d say.

      You will be happy to see that Rockford Lhotka takes a very similar approach with his CSLA.NET framework, which is a very respectable and mature implementation.

      I think so many miss the point because so many either do client-server (NOT n-tier) development and/or they only have a single datasource to be concerned with. I speak from experience, I for a time was the same, until I worked in an environment dealing with multiple datasources. Let alone the notion of “domain objects” that span an organization, as is the case in a B2B or an enterprise scenario which obviously most definitely deals with multiple datasources. Then, not only do you have to worry about abstracting the “business” side of it, you also have to worry about the distribution and transmission of it. Then you get into Remoting, legacy DCOM or RPC, or if fortunate, a contemporary SOA environment with nice clean message-oriented data and service contracts. In this case, it can get even more complicated because now you introduce DTOs (data contracts) into the puzzle.

      Nonetheless, I personally think its OK to have a lightweight data layer and no business layer, if you are SURE that is all you need. Perhaps your business logic is all in the database, or perhaps it is so minuscule that it doesn’t hurt to embed it in your ORM code. That said, if the system has any size to it (at least 80K+ lines of code excluding front-end), I’m betting you are going to paint yourself into a corner without a true business layer.

      Randolph, perhaps could dedicate a post or write-up on this to help bring clarity to this.

      – Timex

  4. Dharmesh said

    Hi Randoplh,

    since long time i had question in my regarding this. where should linq to sql be fit in n-tier architecture? and why we should keep two business object for same entity (business class and auto generated entity class)? but you have replied to these question very nicely. i have gone through your all 4 articles and created 3-tier architecture. but i m bit confused from where GetCustomerId will be called? it should be from Presentation Layer (web page).

    Thanks,
    Dharmesh

  5. Dharmesh said

    Hi

    Can you elobrate link between webpage (pl) and business layer?

    How getCustomerByID will be called from web page?

    Dharmesh

Sorry, the comment form is closed at this time.

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: