New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.

DAL 2 - Caching, Scoping and Custom Mappings

This is the third blog in my series describing the new DAL 2 data layer that we are introducing in DNN 7.  In the first I gave an introduction into why we were introducing a new data Layer, and some of the basic features it provides, and in the second article I introduced the new built in IRepository of T implementation.

Custom Mappings

The simple repository introduced in the previous blog is great for simple modules.  However, in the previous blog we had to make some changes to our TaskInfo class and Tasks table to make everything work using PetaPoco’s mapping conventions.  However, PetaPoco supports an IMapper interface and, in the DAL 2, we have implemented a custom IMapper implementation (PetaPocoMapper) that provides support for three Attributes which are defined in the DotNetNuke.ComponentModel.DataAnnotations namespace.  For those of you who have used Entity Framework or LINQ 2 Sql these are similar to the attributes used in those frameworks.

  • TableName - As mentioned in the previous blog, PetaPoco’s default mapping convention for table name is to map classes to a table that is the plural of the class’s name.  The TableName Attribute allows us to specify the actual Table Name as a class level Attribute.
  • ColumnName - PetaPoco’s default mapping maps object properties to columns which have the same name.  The ColumnName Attribute allows us to define a column name that the property maps to.
  • PrimaryKey - We can define the Primary Key column for our table as a class level Attribute.

Use of these attributes is demonstrated in Listing 1, where we show the original TaskInfo object decorated with custom mapping attributes to map to the Tasks table.  This ability to map the properties to columns means that we can be flexible with our naming.

Listing 1: The TaskInfo Model


The TaskInfo class should now map correctly to the Tasks table from the previous blog - Listing 2.

Listing 2: The Create Table SQL to create the Tasks Table


The DAL 2 PetaPocoMapper class also takes care of the table prefix or object qualifier.  (Note: There is a bug in the CTP which means that object qualifiers don’t actually work - this bug will be fixed in the next pre-Release package of DNN 7.).


It can often be unnecessary and lead to poor performance to go to the database every time we need a collection of tasks or even a single task.  In the DotNetNuke core we make extensive use of in-memory cache’s to deliver the best performance possible. 

Usually items are cached in a collection and if individual items are required they are retrieved using a LINQ query on the in-memory collection.  The DAL 2 provides a very simple caching mechanism, through the use of a fourth Attribute.  The Cacheable attribute allows the developer to define the cache key, the priority and the timeout, as shown in Listing 3.

Listing 3: Adding the Cacheable Attribute


Under the covers the DAL 2 calls DotNetNuke’s built in caching support, so all the normal rules on object caching are applied.  For example, caching is disabled if the Host Setting is set to None.  But for module developers, all you need to do to add support for caching is to add the cacheable attribute. 

Most of the methods of the repository class are aware of the attribute and do the appropriate thing: Get methods check the cache if caching is enabled and update/insert/delete methods clear the cache when called - the exceptions being the methods which take a "SqlCondition” parameter.  This can be seen by looking at the code in Listings 4 and 5.

Listing 4: RepositoryBase’s Get method


Listing 5: The RepositoryBase’s Delete method


Ignoring the IsScoped property for now, the Get method checks if the class T is cacheable.  If it is cacheable it calls DotNetNuke’s GetCachedData utility method, which takes a delegate as a callback to use if the cache has expired - in this case GetInternal(). If T is not cacheable the GetInternal() is called directly.  GetInternal is implemented in the PetaPocoRepository class and is shown in Listing 6.

Listing 6: PetaPocoRepository’s GetInternal method



So now we have the ability to modify our custom mappings through attributes and the ability to control caching, but we still are working with all the data in our module, rather than just the data for one specific instance - or for some modules for one specific portal.

To solve this problem the DAL 2 provides a Scope attribute.  The Scope attribute identifies a property of the object which is used to scope the data.  In most cases this would be the module Id but by keeping this generic we can support different types of scoping - portal Id or user Id as an example.

Lets look at our TaskInfo class after adding the Scope attribute (as well as a ModuleID property) - Listing 7.

Listing 7: The TaskInfo class updated to scope by ModuleID


We also have to update our Table as well so it has a ModuleID column - LIsting 8.

Listing 8: Updated Create Table SQL to include the ModuleID


And finally we have to make a couple of minor changes to the TaskController class - Listing 9.

Listing 9: Updated TaskController methods to handle the ModuleId Scope


Notice that the Repository provides overloads for the Get and GetById method which are used to pass the scope value - in this case the moduleId.

Under the covers the Repository knows that the scope value “moduleId” refers to the Scope column “ModuleID” and generates the appropriate WHERE clause, to query the database.  The cool thing is that this works with the cacheable attribute, so that if the class is both scoped and cacheable then there are separate cached collections for each scope value. 

This post is cross-posted from my personal blog


great article charles, thanks.

Is there a way to clear the cache myself. For example, I have a product table but I also have a products_View which is a sql server view. I use the repository to delete the product but I need to take the product records out of the cache that I have for the products_View. The products view is declared just like a poco table. So can I access and clear a single item from the cache for other poco objects? The clearCache method in listing 5 does not seem to be a public member of the repository/context.
Jordan Monday, December 16, 2013 1:00 PM (link)
Charles Nurse
You can use the DataCache.RemoveCache(cachekey) method to remove any item from the cache. If you use the cacheable attribute then the first parameter is the key.
Charles Nurse Monday, December 16, 2013 1:54 PM (link)
thanks Charles,

So the following will remove all items with the cache key "ProductList_Short_Active":


Is there a way to remove just one item or do I have to clear the entire cache?
Jordan Tuesday, December 17, 2013 4:26 PM (link)
Max Matt
Are multiple primary keys supported?
Max Matt Sunday, October 26, 2014 12:01 PM (link)

Comment Form

Only registered users may post comments.


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Daniels (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out