Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C# 4.0
Tip/Trick

How to Request Presentation Objects with PresentationRequestor

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
12 May 2015CPOL5 min read 11.3K   2   2
This tip is a tutorial that explains how to use PresentationRequestor Nuget package.

Introduction

In common N-tiers applications, developers have to create services that return presentation objects. The services often have filters (identifier, criteria) and/or paging as parameters. The structure of such a service is pretty straightforward: it looks for the business objects based on the specified criteria, and builds the associated presentation objects to return to the clients. Very often, for a single entity, developers will have to create more than one service because the desired presentation objects are different, or the criteria are too different or too many for a single service.

PresentationRequestor will help the developers with this task, by offering a single generic class that returns the desired presentation objects based on criteria specified as Linq expressions. It is therefore possible to replace all the services that the developers had to implement by one single service.

Installation

This library is hosted in Nuget.org site. To install it under Visual Studio, we can type "PresentationRequestor" in the search form or simply type "Install-Package PresentationRequestor" in the Package Manager console. 

This library is making use of "PresentationMapper" Nuget package (which is declared as a dependent library, so it will be automatically downloaded with this one).

You can find a tutorial of "PresentationMapper" here.

Using the Code

Using this tool is very similar to using entities with Entity Framework. We request the objects by specifying fluent code such as "Where", "ToList", "OrderBy", etc.

Sample Classes

First, we need some sample classes to work with.

The presentation classes are as follows:

C#
public class PresentationClass
{
    public virtual int Key { get; set; }
    public virtual string PresentationName { get; set; }
    public virtual PresentationSubClass[] SubClasses { get; set; }
}

public class PresentationSubClass
{
    public int SomeInt { get; set; }
    public bool? SomeBool { get; set; }
    public string Name { get; set; }
    public PresentationClass Parent { get; set; }
}

The business classes are as given below:

C#
[Presentation(typeof(PresentationClass))]
public class BusinessClass
{
    [Key]
    public virtual int Key { get; set; }
    [LinkTo("PresentationName")]
    public virtual string BusinessName { get; set; }
    public virtual IList<BusinessSubClass> SubClasses { get; set; }
}

[Presentation(typeof(PresentationSubClass))]
public class BusinessSubClass
{
    [Key]
    public int SomeInt { get; set; }
    public string Name { get; set; }
    public bool? SomeBool { get; set; }
    public BusinessClass Parent { get; set; }
}

We can see here that we have mapped BusinessClass to PresentationClass, and that BusinessName property of BusinessClass is mapped to PresentationName of PresentationClass. The Key attribute is needed here because we're using Entity Framework to store our data.

ReaderService Class

The ReaderService provided by this library lets us request the presentation objects.

We must get an instance of this class by specifying an object type as argument. 

What is this object argument? Why an object type?

In fact, this library can handle any implementation of a custom interface IDataContext (see "Custom implementation of IDataContext"), but in the common scenario, we work with Entity Framework. This library does not include Entity Framework package (we don't need it in the custom IDataContext case), so we pass the DbContext instance as an object to the constructor of ReaderService, and the tool will automatically instantiate and work with an internal implementation of IDataContext.

ToList

Let's start with the "ToList" method that returns a collection of objects:

C#
using (var db = new DbTestContext())
{
    var result = new ReaderService<PresentationClass>(db).ToList();
}

As we can see, this is pretty easy to use. First, we get the instance of the DbContext. Then we pass it to the constructor of ReaderService, whose generic argument is the presentation object we want to query. This code will simply return all the records of BusinessClass converted to PresentationClass.

Now, let's assume that we now have an instance of ReaderService<PresentationClass> called "service".

C#
var service = new ReaderService<PresentationClass>(db);

Where

The Where instruction will let us specify a filter as a Lambda expression:

C#
var result = service.Where(x=>x.PresentationName=="something").ToList();

This will simply return all records of "BusinessClass" having BusinessName equals to "something", converted to the PresentationClass.

The engine will convert the lambda expression (targeting the presentation object) into a new lambda expression that targets the business object and pass it to Entity Framework. The results are then converted to the presentation object (via PresentationMapper library).

SingleOrDefault

The SingleOrDefault instruction will either return an instance of the presentation object, or null if not found.

C#
var result = service.Where(x=>x.PresentationName=="something").SingleOrDefault();

OrderBy, OrderByDescending, ThenBy, ThenByDescending

Use these methods to sort the records (database sort).

C#
var result = service.OrderBy(x=>x.PresentationName).ThenBy(x=>x.Key).ToList();

Skip, Take

For paging, Skip and Take work like the Entity Framework:

C#
var result = service.Skip(4).Take(3).ToList(); 

Include

Now, this is interesting. The Include method will indicate that sub objects must be included in the query (join database operation), but it's also an indication that the returned presentation object must contain such sub objects. Indeed, by default, sub-objects are not included in the presentation object.

For example:

C#
var result = service.Where(x=>x.PresentationName=="something").SingleOrDefault();

result will have its "SubClasses" property equals to null (even if the business property actually contain data).

Whereas in the example below, it will contain the data:

C#
var result = service.Where(x=>x.PresentationName=="something")
    .Include(x=>x.SubClasses)
   .SingleOrDefault();

Find

The Find instruction returns the object whose identifier matches the values specified. 

C#
var result = service.Find(5);

Note: In Entity Framework, it is not possible to use Include along with Find method. But in this library, we can use the Include method because we want to include the sub objects in the returned result. However, the join will not be performed in the database, but instead lazy loading will be used.

C#
var result = service.Include(x=>x.SubClasses)
   .Find(5);

Custom Implementation of IDataContext

If we don't want to use Entity Framework, we can use any implementation of a custom interface IDataContext:

C#
public interface IDataContext
 {
     /// <summary>
     /// Get an instance of an IDbSet
     /// </summary>
     /// <typeparam name="TBusiness">Business type.</typeparam>
     /// <returns>Returns the IDbSet associated to the specified generic type.</returns>
     IDbSet<TBusiness> DbSet<TBusiness>() where TBusiness:class;
 }

IDataContext exposes just one method "DbSet<>()" that is called when a new request is performed on a set.

IDbSet is an interface that handles sets of data (similarly to the IDbSet on Entity Framework):

C#
/// <summary>
/// Interface representing sets of data.
/// </summary>
/// <typeparam name="TBusiness">Business type.</typeparam>
public interface IDbSet<TBusiness>: IQueryable<TBusiness> where TBusiness:class
{
    /// <summary>
    /// Include paths.
    /// </summary>
    /// <param name="path">Linq expression
    /// representing the relational sub elements to include in the request.</param>
    /// <returns>The current IDbSet instance for fluent usage.</returns>
    IDbSet<TBusiness> Include<TProperty>(Expression<Func<TBusiness, TProperty>> path);

    /// <summary>
    /// Finds an entity with the given primary key values.
    /// </summary>
    /// <param name="ids">The values of the primary key for the entity to be found.</param>
    /// <returns>The business entity corresponding to the specified identifier.</returns>
    TBusiness Find(object[] ids);
}

The IDbSet exposes two methods "Include" and "Find". If the developer doesn't want to implement these methods (throw an exception instead), the respective methods of ReaderService class won't work. 

But more importantly, the IDbSet inherits from IQueryable<> interface. This is also what the Entity Framework sets implement to convert Linq queries into ADO commands. The implementation of this interface requires an implementation of an IQueryProvider, which is by far the most difficult task to do.

There are a few guides we can find to help us with the implementation of an IQueryable interface, so I won't cover this topic here.

Once we have our implementation of IDataContext, and IDbSet, we can use it as the parameter required for the ReaderService class.

C#
var dataContext = new MyDataContext();
var service = new ReaderService<PresentationObject>(dataContext);

Using PresentationRequestor over WCF

In the next article, we'll see how we can use this tool over WCF.

History

  • 12th May, 2015: Initial version
  • 22nd June, 2015: Link to next article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralDomain entity knowing about DTO is not good Pin
Alewmt14-May-15 0:43
professionalAlewmt14-May-15 0:43 
GeneralRe: Domain entity knowing about DTO is not good Pin
HUONG Minh-Luong14-May-15 3:09
HUONG Minh-Luong14-May-15 3:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.