|
Domain Objects Caching Pattern for .NET |

Wednesday, 06 December 2006
|
Abstract Caching greatly improves application performance because it reduces expensive trips to the database. But, if you want to use caching in your application, you must decide what to cache and where to put your caching code. The answer is simple. Cache your domain objects and put caching code inside your persistence classes. Domain objects are central to any application and represent its core data and business validation rules. And, while domain objects may keep some read-only data, most of the data is transactional and changes frequently. Therefore, you cannot simply keep domain objects as "global variables" for the entirety of your application because the data will change in the database and your domain objects will become stale, thereby causing data integrity problems. You'll have to use a proper caching solution for this. And, your options are ASP.NET Cache, Caching Application Block in Microsoft Enterprise Library, or some commercial solution like NCache from Alachisoft. Personally, I would advise against using ASP.NET Cache since it forces you to cache from presentation layer (ASP.NET pages) which is bad. The best place to embed caching in your application is your domain objects persistence classes. In this article, I am extending an earlier design pattern I wrote called Domain Objects Persistence Pattern for .NET. I am going to show you how you can incorporate intelligent caching into your application to boost its performance and what considerations you should keep in mind while doing that. Domain Objects Caching Pattern attempts to provide a solution for domain object caching. The domain objects in this pattern are unaware of the classes that persist them or whether they're being cached or not, because the dependency is only one-way. This makes the domain object design much simpler and easier to understand. It also hides the caching and persistence code from other subsystems that are using the domain objects. This also works in distributed systems where only the domain objects are passed around. Scope Domain objects form the backbone of any application. They capture data model from the database and also the business rules that apply to this data. It is very typical for most subsystems of an application to rely on these common domain objects. And, usually applications spend most of their time in either loading or saving these domain objects to the database. The actual "processing time" of these objects is very small specially for N-Tier applications where each "user request" is very short. This means that performance of the application depends greatly on how quickly these domain objects can be made available to the application. If the application has to make numerous database trips, the performance is usually bad. But, if the application caches these objects close-by, the performance improves greatly. At the same time, it is very important that domain object caching code is kept in such a central place that no matter who loads or saves the domain objects, the application automatically interacts with the cache. Additionally, we must hide the caching code from the rest of application so we can take it out easily if needed. Solution Therefore, the best place to embed caching code is in the persistence classes. This ensures that no matter which part of the application issues the load or save call to domain objects, caching is appropriately referenced first. This also hides all the caching code from rest of the application and lets you replace it with something else should you choose to do so. Domain and Persistence Classes
Sample Application Below is an example of how a client application will use this code.
The code above shows you the overall structure of your classes for handling domain objects persistence and caching. As you can see, there is clear-cut separation between the domain and persistence classes. And, there is an additional FactoryProvider class that lets you hide the persistence implementation from rest of the application. However, the domain objects (Employee in this case) moves around throughout the application. Creating Cache Keys Most cache systems provide you with a string-based key. At the same time, the data that you cache consists of various different classes ("Customers", "Employees", "Orders", etc.). In this situation, an EmployeeId of 1000 may conflict with an OrderId of 1000 if you keys do not contain any type information. Therefore, you need to store some type information as part of the key as well. Below are some suggested key structures. You can make up your own based on the same principles.
Caching in Transactional Operations Most transactional data contains single-row operations (load, insert, update, and delete). These methods are all based on primary key values of the object and are the ideal place to start putting caching code. Here is how to handle each method:
Below is a sample Load method with caching logic included. Remember, you're only loading a single object (single row) from the database.
Please note a few things here.
Caching Relationships Domain objects usually represent relational data coming from a relational database. Therefore, when you cache them, you have to keep in mind their relationships and cache the related objects as well. And, you also have to create "dependency" between the object and all its related objects. The reason being that if you remove the object from the cache, you should also remove all its related objects so there is not data integrity problems. Below is a code example of how to specify relationships in the cache.
In the above example, you'll notice that a collection is being returned from the database and each object inside the collection is stored individually in the cache. Then, the collection is being cached as a single-item but with a cache dependency on all the individual objects in the collection. This means that if any the individual objects is updated or removed in the cache, the collection is automatically removed by the cache. This allows you to maintain data integrity in caching collections. You'll also notice in the above example that the collection has a cache dependency on the "primary object" whose related objects the collection contains. This dependency also means that if the primary object is removed or updated in the cache, the collection will be removed in order to maintain data integrity. Caching in Query Methods A query method returns a collection of objects based on the search criteria specified in it. It may or may not take any runtime parameters. In our example, we have a FindByTitle that takes "title" as a parameter. Below is an example of how caching is embedded inside a query method.
In the above example, just like the relationship method, you'll notice that a collection is being returned from the database and each object inside the collection is stored individually in the cache. Then, the collection is being cached as a single-item but with a cache dependency on all the individual objects in the collection. This means that if any the individual objects is updated or removed in the cache, the collection is automatically removed by the cache. This allows you to maintain data integrity in caching collections. Applications in Server Farms The above pattern works for both single-server or server-farm deployment environments. The only thing that must change is the underlying caching solution. Most caching solutions are for single-server environments (e.g. ASP.NET Cache and Caching Application Block). But, there are some commercial solutions like Alachisoft NCache (http://www.alachisoft.com) that provide you a distributed cache that works in a server farm configuration. This way, your application can use a cache from any server in the farm and all cache updates are immediately propagated to the entire server farm. Conclusion Author: Iqbal M. Khan works for Alachisoft, a leading software company providing O/R Mapping and Clustered Object Caching solutions for .NET. You can reach him at iqbal@alachisoft.com or visit Alachisoft at www.alachisoft.com. Article Source: http://www.ArticleBlast.com |
||||||
You are welcome to publish this article free of charge on your website, newsletter, or e-zine, provided:
- You don't change the article in any way
- You include the entire article, including the "about the author" box
- All hyperlinks must remain intact, including email addresses, and the link to ArticleBlast.com at the bottom
- In doing so you agree to indemnify the article's author, and ArticleBlast.com and its directors, officers, employees and agents from and against all losses, claims, damages and liabilities which arise out of its use
- It is also recommended that you provide a courtesy copy of your publication to the author of the article
