The Business logic layer: Active Record Pattern

Active Record Pattern is popular pattern that is especially effective when the underlying data base model matches the domain model. i.e Typically a business object exists for each and every table in the database

  • The business object represents a single row in table and contains data and behaviour
  • In Active Record Pattern each business object is responsible for its own persistence and business logic
  • Active Record Pattern is great for simple applications that have one to one mapping between data model and Business model
  • It is also good to use if you are building applications with “data first” approach
  • In the .NET world, one of the most popular open source Active Record frameworks is
    the Castle ActiveRecord project that is built upon NHibernate

Implementing Active Record Pattern
A Typical example for Active Record Pattern will be Blogging Application having posts ad comments.. below is the class representation

Create the following two tables..

  • Create a new Solution named ASPPatterns.Chap4.ActiveRecord
  • Add a new C# class library to the solution named ASPPatterns.Chap4.ActiveRecord.Model
  • Add new MVC web application named ASPPatterns.Chap4.Active Record.UI.MVC.
  • Add references to castleproject to the solution
  • Add the following two model classes Comment and Posts in ASPPatterns.Chap4.ActiveRecord.Model

[ActiveRecord("Comments")]
    public class Comment :ActiveRecordBase<Comment>
    {
        [PrimaryKey]
        public int Id { get; set; }
        [Property]
        public string  Text { get; set; }
        [Property]
        public string Author { get; set; }
        [Property]
        public DateTime DateAdded { get; set; }
        [BelongsTo("PostId")]
        public Post Post { get; set; }

    }

 [ActiveRecord("Posts")]
    public class Post :ActiveRecordBase<Post>
    {
        [PrimaryKey]
        public int Id { get; set; }
        [Property]
        public string Text { get; set; }
        [Property]
        public DateTime DateAdded { get; set; }

        public string ShortText
        {
            get
            {
                if(Text.Length>20)
                {
                    return Text.Substring(0, 20) + "......";
                }
                return Text;
            }
        }
        [HasMany]
        public IList<Comment> Comments { get; set; }

        public static Post FindLatestPost()
        {
            SimpleQuery<Post> post =
                new SimpleQuery<Post>(@"from post p
                          order by p.DateAdded desc");

            return (Post) post.Execute()[0];
        }
    }

Advertisements

The Business logic layer: Transaction Script pattern

There are Typically 4 Popular/known Patterns to design/build the domain.. which are

  • Transaction Script Pattern
  • Active Record Pattern
  • Anemic Model Pattern
  • Domain Model Pattern

Not all applications are equal, and require complex architecture to encapsulate Business logic of a system..As a dev..its important to understand the strengths and weakness of all the domain logic patterns..

In this blog… we shall discuss on Transaction ScriptPattern

Transaction Script Pattern

  • Of the four domain logic patterns, Transaction Script Patterns is easiest to Understand and get up running with
  • Transaction Script Patterns follows a Procedural style of development rather than Object Oriented Approach..
  • How Transaction Pattern is implemented..?
    Typically A single static class corresponding to your business transaction will be created and all the workflow(business rules,validation etc) which is required to complete the business transaction will be pertained in that class.

    When Transaction Script Patterns should be implemented..?
    Transaction Script Pattern is great for Small Applications, with little or no logic and mostly not likely to grow like a monster in future..

    Example source code for a Typical Transaction Script Pattern

    public static class HolidayService
        {
            public static bool BookHolidayFor(int employeeId,DateTime from,DateTime to)
            {
                bool booked = false;
                TimeSpan numberOfDaysRequestedForHolidays = to - from;
    
                if(numberOfDaysRequestedForHolidays.Days>0)
                {
                    int holidaysAvailabile = GetHolidaysRemainingFor(employeeId);
    
                    if(holidaysAvailabile >= numberOfDaysRequestedForHolidays.Days)
                    {
                        SubmitHolidayBookingFor(employeeId, from, to);
                    }
    
                }
    
    
    
            }
    
            private static void SubmitHolidayBookingFor(int employeeId, object from, object to)
            {
                // implementation
            }
    
            private static int GetHolidaysRemainingFor(int employeeId)
            {
               // implementation
            }
    
            public static List<EmployeeDTO> GetAllEmployeesOnLeaveBetween(
    DateTime From, DateTime To)
            {
                //  implementation
            }
    
            public static List<EmployeeDTO> GetAllEmployeesWithHolidayRemaining()
            {
                //  implementation
            }
    
            
        }
        public class EmployeeDTO
        {
    
    
        }
    

    As you can see , the entire Business Logic is encapsulated in methods..example,here BookHolidayFor is responsible for data retrieval,validations,Business logic to determine if Holiday can be taken..

    This type of Procedural Programming is fine if you are dealing with small application and business logic is not going to expand further drastically..

    But if you know that your application will grow, then you might want to rethink if you are going for this pattern…its is recommended to go for more scalable pattern like Active Record Pattern.. which i will discuss in the next blog..

    Separating Your Concerns- Antidote to Smart UI Part 5

    So in the previous blog we have created IDiscountStrategy and applied it to  NullDiscountStrategy and TradeDiscountStrategy Classes.

    We have only created Discount Pattern here… and we need to apply this on Price Object and driving factor regarding which Discount Pattern to be applied will be decided by Customer Type.So in order to apply Discount pattern on Price object lets create DiscountFactory class which does this job.

     public static class DiscountFactory
        {
            public static IDiscountStrategy GetDiscountStrategyFor(CustomerType customerType)
            {
                switch (customerType)
                {
                    case CustomerType.Trade:
                        return new TradeDiscountStrategy();
                    default:
                        return new NullDiscountStrategy();
                }
    
            }
    
        }
    

    With discount Strategies in place .. now lets implement Price Object…

     public class Price
        {
            private IDiscountStrategy _discountStrategy = new NullDiscountStrategy();
            private decimal _rrp;
            private decimal _sellingPrice;
            public Price(decimal sellingPrice,decimal rrp)
            {
                _rrp = rrp;
                _sellingPrice = sellingPrice;
            }
            public void SetDiscountStrategyTo(IDiscountStrategy discountStrategy)
            {
                _discountStrategy = discountStrategy;
            }
            public decimal SellingPrice
            {
                get { return _discountStrategy.ApplyExternalDiscountsTo(_sellingPrice); }
            }
            public decimal RRP
            {
                get { return _rrp; }
            }
            public decimal Discount
            {
                get
                {
                    if(RRP&gt;SellingPrice)
                    {
                        return RRP - SellingPrice;
                    }
                    else
                    {
                        return 0;
                    }
                }
            }
            public decimal Savings
            {
                get
                {
                    if (RRP &gt; SellingPrice)
                        return (1 - SellingPrice / RRP);
                    else
                        return 0;
                }
            }
        }
    

    Now we need to apply this discount Pattern to Products List which we will do thru an Extension method

        public static class ProductListExtensionMethod
        {
            public static void Apply(this IList<Product>;products,
                IDiscountStrategy discountStrategy)
            {
                products.ToList().ForEach
                    (p =&gt; p.Price.SetDiscountStrategyTo(discountStrategy));
    
            }
        }
    

    Domain Service

    with Domain in place.. we need to have a service in domain so that client(typically service layer ) can communicate with Domain layer.. lets create a Domain Service(name it Product Service)

    public  class ProcuctService
        {
            private IProductRepository _productRepository;
            public ProcuctService(IProductRepository productRepository)
            {
                _productRepository = productRepository;
            }
            public IList<Product? GetAllProductsFor(CustomerType customerType)
            {
                IDiscountStrategy discountStrategy =
                    DiscountFactory.GetDiscountStrategyFor(customerType);
    
                IList<Product> products = _productRepository.FindAll();
                products.Apply(discountStrategy);
    
                return products;
            }
    
    
        }
    

    Now Domain Service layer is in player.. lts implement Service layer which would communicate with Domain Service layer

    
    public class ProductService
        {
            private model.ProcuctService _productService;
    
            public ProductService(model.ProcuctService productService)
            {
                _productService = productService;
            } 
    
            public ProductListResponse GetAllProductsFor(
                ProductListRequests productListRequest)
            {
                ProductListResponse productListResponce =
                    new ProductListResponse();
                try
                {
                    IList<model.Product> productEntities =
                       _productService.GetAllProductsFor(productListRequest.CustomerType);
    
                    productListResponce.Products =
                        productEntities.ConvertToProductListViewModel();
    
                    productListResponce.Success = true;
                   
                }
                catch (Exception ex)
                {
                    productListResponce.Success = false;
                    productListResponce.Message = ex.Message.ToString();
    
                    throw;
                }
                return productListResponce;
            }
        }
    
    

    Separating Your Concerns- Antidote to Smart UI Part 4

    Now lets start building Service layer

    ServiceLayer

    • The role of Service layer is to act as entry point in to application..sometimes it is known as a FACADE
    • Service layer provides the Presentation Layer with a strongly Typed View model, sometimes called Presentation Model
    • Add a new class to ASPPatterns.Chap3.Layered.Service project named ProductViewModel
    • 
      public class ProductViewModel
          {
              public int ProductId { get; set; }
              public string Name { get; set; }
              public string  RRP { get; set; }
              public string SellingPrice { get; set; }
              public String Discount { get; set; }
              public string Savings { get; set; }
      
          }
      
    • Client will be interacting with Service layer and for this we will use REQUEST-RESPONSE Messaging Pattern
    • From client we will be getting a Request to Service and Request will be of CustomerType. So create a Request based on CustomerType
    •  public class ProductListRequestcs
          {
              public CustomerType CustomerType { get; set; }
          }
      
    • Response from Service would be of ProductViewModel along with Success/Failure message..
       public class ProductListResponse
          {
              public bool Success { get; set; }
              public string Message { get; set; }
              public IList<ProductViewModel> Products { get; set; }
      
          }
      
    • If you observe in Response we are sending ProductViewModel as Response.. so we need to have a mechanism to convert Products in to ProductViewModels.. so lets build this mechanism..
    • Below class is an extension method to Products, which will Transform Products to ProductViewModels
    •   public static IList<ProductViewModel> ConvertToProductListViewModel(this IList<Model.Product> products)
              {
                  IList<ProductViewModel> productViewModels = new List<ProductViewModel>();
      
                  foreach (var product in products)
                  {
                      productViewModels.Add(product.ConvertToProductViewModel());
                  }
      
                  return productViewModels;
              }
      
    • The below class is an extension method to Product , which will convert Product to ProductViewModel
    •  public static ProductViewModel ConvertToProductViewModel(this Model.Product product)
              {
                  ProductViewModel productViewModel = new ProductViewModel();
      
                  productViewModel.ProductId = product.Id;
                  productViewModel.Name = product.Name;
                  productViewModel.RRP = string.Format("{0:C}", product.Price.RRP);
                  productViewModel.SellingPrice = string.Format("{0:C}", product.Price.SellingPrice);
      
                  if(product.Price.Discount > 0)
                  {
                      productViewModel.Discount = string.Format("{0:C}", product.Price.Discount);
                  }
      
                  if (product.Price.Savings > 0 && product.Price.Savings<1)
                  {
                      productViewModel.Savings = product.Price.Savings.ToString("#%");
                  }
                  return productViewModel;
              }
      

      Now if you remember we have yet to build our domain… lets start Building Domain Domain

      Domain Layer

      Gear Up!!!!!… we are going to implement some Patterns here…

      See the below diagram…

    • We have Product Class and Product Class contains price class which will implement Discount Strategy
    • What is the need of Strategy Pattern in our implementation..??
      Strategy Pattern enables algorithms to be selected and changed at runtime and there is a need for our Price object to display Discount based on Customer Type. so we are going to apply Discount Algorithms to Price Object.

      Lets implement Strategy Pattern Discount Strategy

    • Create an Interface IDiscountStrategy in ASPPatterns.Chap3.Layered.Model
    • public interface IDiscountStrategy
          {
              decimal ApplyExternalDiscountsTo(decimal originalSalesPrice);
      
          }
      
    • Now we have created Interface IDiscountStrategy , lets add two implementations of Discount Strategy TradeDiscountStrategy and NullDiscountStrategy
    • Trade discount strategy will apply discount to original sales price..see below implementation
    • 
      public class TradeDiscountStrategy : IDiscountStrategy
          {
              public decimal ApplyExternalDiscountsTo(decimal originalSalesPrice)
              {
                  decimal price = originalSalesPrice;
      
                  price = price * .095M;
                  return price;
      
              }
          }
      
      
    • If you observe below implementation of NullDiscountStrategy, we are employing Null Object Pattern here
    •     public class NullDiscountStrategy : IDiscountStrategy
          {
              public decimal ApplyExternalDiscountsTo(decimal originalSalesPrice)
              {
                  return originalSalesPrice;
              }
          }
      

    Separating Your Concerns- Antidote to Smart UI Part 3

    Now.. if you remember our use case.. we have products.. and price of the products will vary based on Type of Customer..

    So to proceed further , let us create two objects Product and Customer(since customer will be a type..it should be an enum in our Domain model “ASPPatterns.Chap3.Layered.Model”.

    Product.cs

    
    public class Product
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public Price Price { get; set; }
        }
    
    

    Since Price of the product has a behaviour now..it is going to vary by the Customer Type.. it should be an object.. so for now create an empty price class as shown below..we will see implementation of Price class later(why..?? since we are going to apply new patterns in this class..)

     public class Price
        {
        }
    

    Now create CustomerType enum

     public enum CustomerType
        {
            Standard=0,
            Trade=1
        }
    

    lets retro where we are heading…

    Typical Three Layered Architecture

    This is what we are going to do…

  • Presentation Layer : we are half way done here..if you remember in previous blog we have created our presentation layer
  • Business Logic Layer : we have only created basic infrastructure i.e we have created Product Class, defined price class and Customer class
  • Data Access Later Yet to start

    Note If you observe the above diagram we will be having two Service classes
    1. First one In Domain model..
    2. One in the service layer..
    Reason for this…??? since we are following Layered architecture… Responsibility of Service class in domain layer will be fetching data from Repository Later and Responsibility of Service class in Service Layer will be interacting with service class in Domian Layer and Giving Presentation Model to Presentation Layer..

    Lets code to get clarity…

    Now we will build repository layer/Data Access layer…

  • As with the Smart UI, you need a database to store the products. Create a database in the WebUI project with the same schema, name, and data that you used in the Smart UI Blog
  • Creating database

    We will be using Linq to SQL here…(this is the first time i am working with LinqtoSQL.. but it rocks…!! will try to post more about LinqToSQL after finishing this book)

  • Add a new Linq to SQL class to the ASPPatterns.Chap3.Layered.Repository project
    by right-clicking the project name and selecting Add ➪ New Item. Then select Linq to SQL Classes,and name the class Shop.dbml
  • With the Server Explorer window open, drag the Products table onto the design surface. Visual Studio creates a Linq to SQL entity named Product
  • Now What.. what is the use of Linq to SQL.. you will see now..

  • Create Interface IProductRepository in ASPPatterns.Chap3.Layered.Model Project..Why a Repository Interface in Model ..?? Domain Service Layer will interact with Data Layer to retrieve products. and we don’t want Model Project to be concerned with what kind of technologies will be used to query the data
  • public interface IProductRepository
        {
            IList<Product> FindAll();
        }
    
  • Now create Concrete Implementation of IProductRepository in ASPPatterns.Chap3.Layered.Repository project, by creating class ProductRepository
  •  public IList<Model.Product> FindAll()
            {
                var products = from p in new ShopDataContext().Products
                               select new Model.Product
                               {
                                   Id = p.ProductId,
                                   Name = p.ProductName,
                                   //Price = new Model.Price(p.RRP, p.SellingPrice) -- Price implmentation
                               };
    
                return products.ToList();
    
            }
    
  • Check out line 3 in the above code… since we have implemented LinqToSQl we can directly query over Product table… isn’t it cool
  • coming to line 8 in the above code.. we need to implement Price model..which we will do later and come back here again..
  • With this we have completed implementation of Data Layer … in the next blog we will implement Service layer

    Separating Your Concerns- Antidote to Smart UI Part 2

    ..Honestly to be mentioned.. i have completed the third chapter..and there are lot new stuff which i am unaware of it …it took me for a while to understand some concepts.. i really hope.. i will get my self a clear understanding after completing this Separating Your Concerns- Antidote to Smart UI series…

    in the Book.. first Domain model has been presented and then parts like web services,infrastructure, repo model were built on Domain model.. finally developing Presentation layer/User Experience Layer..

    But In this series i will first start with Presentation Layer…as i said i want to be clear about what i have done in this series..instead of just putting what is in the book

    The below diagram represents the architecture flow which we are going to develop..

    before going in to Presentation layer.. lets build our database as we have done in AntiPattern

  • Create a database in the WebUI project with the same schema, name, and data that you used in the Smart UI exercise
  • User Experience Layer

  • Open the default.aspx source view and edit the HTML markup so it matches what follows:
  • <asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
    
       
    <asp:DropDownList AutoPostBack="true" ID="ddlCustomerType" runat="server">
    <asp:ListItem Value="0">Standard</asp:ListItem>
    <asp:ListItem Value="1">Trade</asp:ListItem>
    </asp:DropDownList>
    <asp:Label ID="lblErrorMessage" runat="server" ></asp:Label>
    <asp:Repeater ID="rptProducts" runat="server" >
    <HeaderTemplate>
    <table>
    <tr>
    <td>Name</td>
    <td>RRP</td>
    <td>Selling Price</td>
    <td>Discount</td>
    <td>Savings</td>
    </tr>
    <tr>
    <td colspan="5"><hr /></td>
    </tr>
    </HeaderTemplate>
    <ItemTemplate>
    <tr>
    <td><%# Eval("Name") %></td>
    <td><%# Eval("RRP")%></td>
    <td><%# Eval("SellingPrice") %></td>
    <td><%# Eval("Discount") %></td>
    <td><%# Eval("Savings") %></td>
    </tr>
    </ItemTemplate>
    <FooterTemplate>
        </table>
    </FooterTemplate>
    </asp:Repeater>
    
    </asp:Content>
    
    

    if you compare the code with Smart UI AntiPattern, this is super clean.. there are no database bound controls in UI.. there are no delete/update/select database bounded controls here…

    For now don’t worry about code behind file..i will revisit this section later again in the series..

    Separating Your Concerns- Antidote to Smart UI

    Separating Your Concerns

    An antidote to smart UI antipattern is the notion of Layering your applications.

    Layering an application is a form of separation of concerns and can be achieved via namespaces,folders or with Separate Projects . Below Figure shows Typical
    ASP.NET enterprise level Layerd Architecture

    Let us rewrite the code which we have written in SmartUI Antipattern.. aligning to Seperation of Concerns…which we have discussed above…

    Refactoring to the principles.. lets start coding…!!

    • Create a new blank solution in Visual Studio and name it ASPPatterns.Chap3.Layered
    • Add a new class library project to the solution by right-clicking the solution name and selecting Add ➪ New Project. Name the new project ASPPatterns.Chap3.Layered.Repository .
    • Add a further three class library projects to the solution named:
    • 1. ASPPatterns.Chap3.Layered.Model
      2. ASPPatterns.Chap3.Layered.Service
      3. ASPPatterns.Chap3.Layered.Presentation

    • Add a new web application to the project by selecting Add ➪ New Project and selecting the Web Application Project. Name the project ASPPatterns.Chap3.Layered.WebUI.
    • Right-click on the ASPPatterns.Chap3.Layered.Repository project and add a project reference to the ASPPatterns.Chap3.Layered.Model project
    • Right-click on the ASPPatterns.Chap3.Layered.Service project and add a project reference to the ASPPatterns.Chap3.Layered.Repository and ASPPatterns.Chap3.Layered
      .Model projects
    • Right-click on the ASPPatterns.Chap3.Layered.Presentation project and add a project reference to the ASPPatterns.Chap3.Layered.Model and ASPPatterns.Chap3.Layered
      .Service projects
    • Right-click on the ASPPatterns.Chap3.Layered.WebUI web application and add a project reference to the ASPPatterns.Chap3.Layered.Model, ASPPatterns.Chap3.Layered.Service,ASPPatterns.Chap3.Layered.Presentation, and ASPPatterns.Chap3.Layered.Repository projects
    • This is how solution looks like…

    in the Smart UI Application, we have written Business logic in the Presentation layer itself..

    Now we will separate this..All domain related stuff goes in to ASPPatterns.Chap3.Layered.Model ..

    will start coding in next blog.. tune in folks .. lots and lots of new stuff is going to come…