Add Data to Cache
After successfully connecting to the cache and gaining a valid cache handle, you can add data to the cache. This data is usually frequently accessed by the application and is not frequently modified. For example, you wish to add the products information of a store into the cache as it is frequently accessed for checking availability. This saves database trips as data can be accessed from the cache instead of accessing the database for each request.
NCache provides the Add() method and its overloads to facilitate adding objects to cache for the first time.
Add Operation Behavior
Add is a one-time operation. The same key cannot be added again if it already exists in the cache. For that you need to Insert it into the cache, which overwrites the value for the existing key.
Add returns CacheItemVersion, a value which internally marks the version of the cache item being added. For each subsequent update of the same item, this version will be updated. This is used in data concurrency scenarios to internally keep track of the updated objects, and is discussed in detail in the chapter Optimistic Locking.
In advanced cases, if data source is configured, data will be added to cache as well as the data source during the Add operation. For more details, refer to the chapter Data Source Providers.
Pre-requisites
- Include the following namespaces in your application:
Alachisoft.NCache.Client
Alachisoft.NCache.Runtime.Exceptions
- The application must be connected to cache before performing the operation.
- Cache must be running.
- Make sure that the data being added is serializable.
- To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
Custom Object
You can add a single object to the cache using various overloads of the Add() method and add() in case of Java.
Warning
If the key already exists, an "OperationFailedException" will be thrown.
The following example adds an object of Product class and its associated key into the cache. This returns CacheItemVersion. If the key already exists, a "Specified key already exists" exception is thrown. The code sample then checks whether the key has been successfully added to cache or not.
Tip
One quick way to verify whether item has been added is to use either properties of the Cache class:
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
try
{
// Pre-condition: Cache is already connected
// Get product from database against given product ID
Product product = FetchProductFromDB(1001);
// Generate a unique cache key for this product
string key = $"Product:{product.ProductID}";
// Add Product object to cache
CacheItemVersion version = cache.Add(key, product);
// Item added in cache successfully
}
catch (OperationFailedException ex)
{
// NCache specific exception
if(ex.ErrorCode == NCacheErrorCodes.KEY_ALREADY_EXISTS)
{
// An item with the same key already exists
}
else
{
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
CacheItem
CacheItem is a custom class provided by NCache which can be used to add data to the cache and also lets you set additional metadata associated with an object of this class. This metadata defines the properties of the item like expiration, dependencies and more. You can refer to all properties of CacheItem here. For Java, please refer to the properties of CacheItem here.
Warning
If the key already exists, an "OperationFailedException" will be thrown.
Tip
One quick way to verify whether item has been added, is to use either properties of the Cache class:
The following example adds a basic CacheItem
containing the Product object into the cache; additional properties will be set against the CacheItem
in successive chapters. If the key already exists, a "Specified key already exists" exception is thrown. The code sample then checks whether the key has been successfully added to cache or not.
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
try
{
// Pre-condition: Cache is already connected
// Get product from database against given product ID
Product product = FetchProductFromDB(1001);
// Generate a unique cache key for this product
string key = $"Product:{product.ProductID}";
// Create a new CacheItem for this product
// You can OPTIONALLY specify multiple properties e.g. Priority, Expiration
// These properties are explained in successive chapters
var cacheItem = new CacheItem(product);
// cacheItem.AbsoluteExpiration = DateTime.Now.AddMinutes(5);
// Add CacheItem to cache
CacheItemVersion version = cache.Add(key, cacheItem);
}
catch (OperationFailedException ex)
{
// NCache specific exception
if(ex.ErrorCode == NCacheErrorCodes.KEY_ALREADY_EXISTS)
{
// An item with the same key already exists
}
else
{
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
CacheItem with Location Affinity
Note
This feature is only available in NCache Enterprise Edition.
You can also add a cache item using NCache's Location Affinity syntax. Location Affinity will store the cache item created with an identical key at the same node so that when the data is fetched from cache, the extra matching cost is saved.
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
try
{
// Pre-condition: Cache is already connected
// Get product from database against given product ID
Product product = FetchProductFromDB(1001);
// Unique product key for this product
string productKey = "Product:1001";
// Create a new CacheItem for this product
var productCacheItem = new CacheItem(product);
// Add CacheItem to cache
CacheItemVersion version = cache.Add(productKey, productCacheItem);
// Get order from database against given order ID
Order order = FetchOrderFromDB(17);
// Unique order key for this order using Location Affinity syntax
// This will create an affinity for this orderKey with the respective productKey
string orderKey = "Order_{Product:1001}";
var orderCacheItem = new CacheItem(order);
// Add order with Location Affinity to cache
CacheItemVersion version = cache.Add(orderKey, orderCacheItem);
}
catch (OperationFailedException ex)
{
// NCache specific exception
if(ex.ErrorCode == NCacheErrorCodes.KEY_ALREADY_EXISTS)
{
// An item with the same key already exists
}
else
{
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
JsonObject
Note
This feature is only available in NCache Enterprise Edition.
You can add a JsonObject
, JsonArray
or JsonValue
to the cache derived from JsonValueBase
class provided by NCache. JsonObject is added in the cache against a unique key which lets you perform further operations using this key. For more detail regarding the topic, please refer to the Cache Data as JSON section.
Note
In order to use JsonValueBase
, please add the following namespace in your application:
Alachisoft.NCache.Runtime.JSON
The following example adds a JsonObject
in the cache along with various attributes.
try
{
// Pre-Condition: Cache is already connected
// Cache is JSON serialized
// Get product from database against given product ID
Product product = FetchProductFromDB(1001);
// Create a unique key for the object
string key = $"Product:{product.ProductID}";
// Create a new JSON object and set attributes
// string values need to be added with JsonValue
var jsonProduct = new JsonObject();
jsonProduct.AddAttribute("ProductID", product.ProductID);
jsonProduct.AddAttribute("ProductName", (JsonValue)product.ProductName);
jsonProduct.AddAttribute("Category", (JsonValue)product.Category);
jsonProduct.AddAttribute("UnitPrice", product.UnitPrice);
jsonProduct.AddAttribute("UnitsInStock", product.UnitsInStock);
// Add object in the cache with the key
cache.Add(key, jsonProduct);
// JsonObject will successfully be added to the cache
}
catch (OperationFailedException ex)
{
if (ex.ErrorCode == NCacheErrorCodes.ATTRIBUTE_ALREADY_EXISTS)
{
// An attribute already exists with the same name
}
else if (ex.ErrorCode == NCacheErrorCodes.REFERENCE_TO_SELF)
{
// No object can contain a reference to itself
}
else
{
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Data Structure
Note
This feature is only available in NCache Enterprise Edition.
You can also add data structures in cache when they are created. Moreover, you can further add data into the data type. For more detail on supported data structures, please refer to the section Data Structures in Cache.
The following code sample shows how a list of Product type can be created in cache against the cache key "ProductList" which must be unique. It then adds Product objects to the list.
Note
In order to use data structures, the following additional namespaces must be added into your application:
Alachisoft.NCache.Client.DataTypes
Alachisoft.NCache.Client.DataTypes.Collections
try
{
// Pre-condition: Cache must be connected
// Specify unique cache key for list
string key = "ProductList";
// Create list of Product type in cache
IDistributedList<Product> list = cache.DataTypeManager
.CreateList<Product>(key);
// Check if the list exists in cache
// using cache.Contains()
// Get products to add to list
Product[] products = FetchProducts();
foreach (var product in products)
{
// Add products to list
list.Add(product);
}
}
catch (OperationFailedException ex)
{
// NCache specific exception
if(ex.ErrorCode == NCacheErrorCodes.KEY_ALREADY_EXISTS)
{
// An item with the same key already exists
}
else
{
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
Bulk Items
NCache also allows synchronous bulk addition of items in a single call to reduce network cost. AddBulk() adds an array of CacheItem to the cache with the corresponding cache keys. The method returns a dictionary of all the keys that fail to add, along with the failure reason. For Java, NCache provides a method of addBulk to add an array of items in the cache.
Although a bulk operation is executed as a single operation, the failure of operations is treated individually. For example, if a bulk of 100 items is added to the cache and 20 of those items already exist in the cache, the remaining 80 items will be added to the cache. The keys of existing 20 items will be returned to the application as a dictionary of failed operations along with the failure reason.
Note
Any keys that fail to add and their failure reason will be returned as an IDictionary
.
The following code adds a bulk of product items to the cache. If there are any keys that failed to add, the keys can be handled according to your business needs.
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
try
{
// Pre-condition: Cache is already connected
// Fetch all products from database
Product[] products = FetchProductsFromDB();
//Create dictionary of items to be added to cache
IDictionary<string, CacheItem> dictionary = new Dictionary<string, CacheItem>();
foreach (var prod in products)
{
string key = $"Product:{prod.ProductID}";
var cacheItem = new CacheItem(prod);
//Add dictionary to cache
dictionary.Add(key, cacheItem);
}
// Add bulk data
IDictionary<string, Exception> keysFailedToAdd = cache.AddBulk(dictionary);
//Check if keys failed to add
if (keysFailedToAdd.Count > 0)
{
foreach (KeyValuePair<string, Exception> entry in keysFailedToAdd)
{
// Check failure reason
if (entry.Value is OperationFailedException)
{
var ex = entry.Value as OperationFailedException;
if(ex.ErrorCode == NCacheErrorCodes.KEY_ALREADY_EXISTS)
{
// An item with the same key already exists
}
}
else
{
// Any other exception
}
}
}
}
catch (OperationFailedException ex)
{
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Asynchronous API
Note
This feature is only available in NCache Enterprise Edition.
Asynchronous operations are performed in the background, so the client does not have to wait for the response from the server to execute further operations. The list of actions to be performed on the cache is maintained in a queue at the client side and a dedicated background thread keeps on sending them to the server side. Hence, all the operations are being executed in a pure asynchronous manner, increasing the efficiency of the client application.
AddAsync returns object of the Task class which can further be used according to the business needs of the client application. NCache provides three different status flags to notify the success or failure of the operation. For Java, addAsync method is used to add items in the cache asynchronously.
IsCanceled: Notifies if the AddAsync function is canceled.
IsCompleted: Notifies if the AddAsync function is completed.
IsFaulted: Notifies if the AddAsync function is faulted.
try
{
// Pre-condition: Cache is already connected
// Get product from database against given product ID
Product product = FetchProductFromDB(1001);
// Generate a unique cache key for this product
string key = $"Product:{product.ProductID}";
// Add Product object to cache
Task task = cache.AddAsync(key, product);
//This task object can be used as per your business needs
if (task.IsFaulted)
{
// Task completed due to an unhandled exception
}
}
catch (OperationFailedException ex)
{
// NCache specific exception
// Exception can occur due to Connection Failure
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Using ICache.Add for Distributed Locking
Due to its versatile nature, another wide use of Add operation is in locking the cache if it is being used by multiple applications.
For example, an environment is set such that as soon as any application connects to the cache, it adds a specific key which is known to all applications. And once the application is done using the cache, it removes the key from the cache. If the key is added successfully, it can proceed to use the cache according to its logic. However, if the key already exists, it means the cache is already being used by an application, and is "locked".
This is described in steps in the following diagram:
App A and App B add the "WorkStarted" key as soon as the cache is started.
The key passed by App A is added to the cache before the one passed by App B.
App B gets a "Specified key already exists" exception. In this scenario, App B will wait for App A to finish its work, i.e., until it can successfully add the "WorkStarted" key.
App A removes the key from the cache once done with its work.
App B adds the key to cache again.
The key is added by App B successfully, locking the cache for other applications.
Additional Resources
NCache provides sample application for Basic Operations at:
- GitHub
- Shipped with NCache: *%NCHOME%\samples\dotnet\BasicOperations
See Also
Update Existing Data in Cache
Retrieve Existing Cache Data
Remove Data from Cache
How to Connect to Cache
Create Cache