Key Dependency Types and Usage
Note
This feature is only available in NCache Enterprise Edition.
There are situations when you want to keep a relationship among related cache
data e.g. an order depends on a product. If the product is no longer available, all the dependent orders need to be removed too. Here you can use key
dependency to maintain this relationship.
Key dependency creates a dependency relationship between cached items.
Note
The dependent item is removed in case of two types of modifications in the master key:
In NCache, dependent cache items and the ones on which others depend are aware
of this relationship. So when an item on which other items depend is removed,
all dependent items will be removed. However vice versa is not possible, i.e. on
removal of the orders, which has dependency on any other item e.g. products, products
will not be removed if any of the orders is updated or removed.
Key(s) can have two types of dependencies:
Multilevel Dependency
A cache item can have a dependency on any number of other items in the cache; resulting in the formation of a chain. The relation in this case will be 1:1 relationship.
For example, there are three data sets in a cache i.e. Products, Orders and OrderDetails. For an order placed on a particular product, the key of the OrderDetails depends on the key of the Orders. Similarly the key of the Orders depends on the key of the Products.
Which means that if the Product is deleted the Order and the OrderDetails are also deleted. The following diagram depicts the scenario visually.

Multiple Dependency
A single item can depend on more than one items in the cache. Similarly that item may depend on further multiple items. This may result in a 1:n relationship between the items.
For example in a cache, if an Order is placed by a Customer which contains a product, the Order depends on the Customer as well as the Product. Similarly, the OrderDetails depend on the Orders.
The following diagram depicts the whole scenario visually.

Here if Customer is deleted, Orders as well as OrderDetails get deleted. Similarly if the Product is deleted, Orders as well as OrderDetails get deleted.
Note
Only the existing keys in cache can be specified for key dependency. Nonexistent key specified for key dependency will result in
OperationFailedException
whereas an object can be specified as being dependent on another key at the time of
addition.
Prerequisites
Add CacheItem to Cache with Key Dependency
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 dependencies, expirations and more.
The Add method adds a new item in the cache whereas the Insert method adds a new item with dependency and if the item already exists in the cache it overwrites its properties.
Important
Note that this API also specifies cache item priority for eviction as well as expiration, so the value for that parameter has been passed as Default
, as it is not discussed here.
The following example adds a CacheItem
order to the cache using the Insert
method, which is dependent on the customer in the cache which means as soon as the customer is updated or deleted, the order of the customer is already deleted from the cache.
try
{
// Pre-Condition: Cache is already connected
// Customer with CustomerID "ALFKI" exists in the cache
Customer customer = FetchCustomerByCustomerID("ALFKI");
// Specify the key of the item
string customerKey = $"Customer: {customer.CustomerId}";
// Get order against the customer from cache
Order order = FetchOrderByCustomerId("ALFKI");
// Generate a unique key for order
string orderKey = $"Order:{order.OrderID}";
// Create a new CacheItem for this order
var cacheItem = new CacheItem(order);
// Create a new dependncy on customer
cacheItem.Dependency = new KeyDependency(customerKey);
// Add/Update item with keydependency
cache.Insert(orderKey, cacheItem);
// For successful addition of cacheitem with dependency
// Update the key and check if cacheitem is present in cache
// This can be done by using
// Cache.Contains()
// Count
}
catch (OperationFailedException ex)
{
// NCache specific exception
if (ex.ErrorCode == NCacheErrorCodes.DEPENDENCY_KEY_NOT_FOUND)
{
// The dependent item does not exist in the cache
}
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
}
try
{
// Precondition: Cache is already connected
// Get customer from database against given customerId
Customer customer = fetchCustomerFromDb("ALFKI");
// Create a unique cache key for this customer
String customerKey = "Customer:" + customer.customerId;
// Get orders against the customer from the cache
Order order = fetchOrdersByCustomerId(customerId);
// Generate a unique key for order
String orderKey = "Order:" + order.orderId;
// Create a new cache item for this order
CacheItem cacheItem = new CacheItem(order);
// Create key dependency
cacheItem.setDependency(KeyDependency(customerKey));
// Insert cache item with key dependency
cache.insert(orderKey, cacheItem);
// For successful addition of cacheItem with dependency
// update the key and check if cacheItem is present in the cache
}
catch (OperationFailedException ex)
{
// NCache specific exception
if (ex.getErrorCode() == NCacheErrorCodes.DEPENDENCY_KEY_NOT_FOUND)
{
// The dependent item does not exist in the cache
}
else
{
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like IllegalArgumentException or NullPointerException
}
try {
// Precondition: Cache is already connected
// Get customer from database against given customerId
val customer = fetchCustomerFromDb("ALFKI")
// Create a unique cache key for this customer
val customerKey = "Customer:" + customer.getCustomerId
// Get orders against the customer from the cache
val order = fetchOrderByCustomerId("ALFKI")
// Generate a unique key for order
val orderKey = "Order:" + order.getOrderId
// Create a new cache item for this order
val cacheItem = CacheItem(order)
// Create key dependency
cacheItem.setDependency(KeyDependency(customerKey))
// Insert cache item with key dependency
cache.insert(orderKey, cacheItem)
// For successful addition of cacheItem with dependency
// update the key and check if cacheItem is present in the cache
}
catch {
case exception: Exception => {
// Handle any errors
}
}
// This is an async method
try
{
// Precondition: Cache is already connected
// Customer "ALFKI" already exists in the cache
let customer = new Customer(this.customerId);
customer = await this.fetchCustomerByCustomerId(this.customerId);
// Create unique key for this customer
let customerKey = "Customer:" + customer.CustomerId;
// Get orders against the customer from cache
let orders = await this.fetchOrdersByCustomerId(this.customerId);
// Create a unique key for this order
let orderKey = "Order:" + orders.OrderId;
// Create a new cacheItem for this order
var cacheItem = new ncache.CacheItem(orders);
// Create a new key dependency on customer
cacheItem.setDependency(new KeyDependency(customerKey));
// Add/update item in the cache with key dependency
this.cache.insert(orderKey, cacheItem);
// For successful addition of cacheitem with dependency
// Update the key and check if cacheitem is present in cache
}
catch (error)
{
// Handle any errors
}
try:
# Precondition: Cache is already connected
# Customer "ALFKI" already exists in the cache
customer = fetch_customer_by_customer_id("ALFKI")
# Create unique key for this customer
customer_key = "Customer:" + customer.get_customer_id()
# Get orders against the customer from cache
order = fetch_order_by_customer_id(customer.get_customer_id())
# Create a unique key for this order
order_key = "Order:" + order.get_order_id()
# Create a new cacheItem for this order
cache_item = ncache.CacheItem(order)
# Create a new key dependency on customer
cache_item.set_dependency(ncache.KeyDependency(customer_key))
# Add / update item in the cache with key dependency
cache.insert(order_key, cache_item)
# For successful addition of cacheitem with dependency
# Update the key and check if cacheitem is present in cache
except Exception as exp:
# Handle errors
Note
To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
Add Key Dependency on Multiple Keys
You can also add key dependency to an item which is dependent on multiple keys. This way a single item can be dependent on multiple items using the Add or Insert method.
The Add
method adds a new item in the cache whereas the Insert
method adds a new item with dependency and if the item already exists in the cache it overwrites its properties.
Important
Note that this API also specifies cache item priority for eviction as well as expiration, so the value for that parameter has been passed as Default
, as it is not discussed here.
The following example adds employee's data in the cache with the dependency of the employee on the territories. If any territory gets updated or deleted from the cache, the employee automatically gets deleted.
// Get product from database against given ProductID
Employee employee = FetchEmployeeByID(1);
// Generate a unique cache key for this product
string key = $"Employee:{employee.EmployeeID}";
// Territories with the keys exist in the cache
string territoryKey1 = "Territory: Westboro";
string territoryKey2 = "Territory: Bedford";
// Insert the keys of the territories in an array
string[] territories = new string[1];
territories[0] = territoryKey1;
territories[1] = territoryKey2;
// Create a new cacheItem containing employee
var cacheItem = new CacheItem(employee);
// Add KeyDependency to employee on territories
cacheItem.Dependency = new KeyDependency(territories);
// Add CacheItem with key dependecy on territories
cache.Insert(key, cacheItem);
// For successful addition of item with dependency
// Update or remove the keys
// Verify if dependent key is present
// Get employee from database against given employeeId
Employee employee = fetchEmployeeFromDb(employeeId);
// Generate a unique cache key for this employee
String key = "Employee:" + employee.employeeId;
// Territories with the keys exist in the cache
String territoryKey1 = "Territory: Westboro";
STring territoryKey2 = "Territory: Bedford";
// Insert the keys of the territories in an array
String[] territories = new String[1];
territories[0] = territoryKey1;
territories[1] = territoryKey2;
// Create a new cache item containing employee
CacheItem cacheItem = new CacheItem(employee);
// Add key dependency to employee on territories
cacheItem.setDependency(KeyDependency(Arrays.asList(territories)));
// Add cache item with key dependency on territories
cache.insert(key, cacheItem);
// For successful insertion of item with dependency
// Update or remove the keys
// Verify if dependent key is present
// Get customer from database against given employeeId
val customer = fetchCustomerFromDb("ALFKI")
// Generate a unique cache key for this customer
val key = "Employee:" + customer.getCustomerId
// Territories with the keys exist in the cache
val territoryKey1 = "Territory: Westbrook"
val territoryKey2 = "Territory: Bedford"
// Insert the keys of the territories in an array
var territories: List[String] = List()
territories = territoryKey1 :: territories
territories = territoryKey2 :: territories
// Create a new cache item containing customer
val cacheItem = new CacheItem(customer)
// Add key dependency to customer on territories
cacheItem.setDependency(KeyDependency(territories))
// Add cache item with key dependency on territories
cache.insert(key, cacheItem)
// For successful insertion of item with dependency
// Update or remove the keys
// Verify if dependent key is present
// Get product from database against productId
let product = await this.fetchProductFromDb(this.productId);
// Create unique cache key for this product
let key = "Product:" + product.ProductID;
// Territories with the keys exist in the cache
let territoryKey1 = "Territory: Chai";
let territoryKey2 = "Territory: Tofu";
// Insert territory keys to the cache
let territories = new String[2];
territories[0] = territoryKey1;
territories[1] = territoryKey2;
// Create a new cache item containing product
let cacheItem = new ncache.CacheItem(product);
// Add key dependency to employee on territories
cacheItem.setDependency(new KeyDependency(territories));
// Add cache item with dependency in the cache
this.cache.insert(key, cacheItem);
// For successful addition of item with dependency
// Update or remove the keys
// Verify if dependent key is present
# Get product from database against productId
product = fetch_product_from_db("1001")
# Create unique cache key for this product
key = "Product:" + product.get_product_id()
# Territories with the keys exist in the cache
territory_key_1 = "Territory: Chai"
territory_key_2 = "Territory: Tofu"
# Insert territory keys to the cache
territories = [
territory_key_1,
territory_key_2
]
# Create a new cache item containing product
cache_item = ncache.CacheItem(product)
# Add key dependency to employee on territories
cache_item.set_dependency(ncache.KeyDependency(territories))
# Add cache item with dependency in the cache
cache.insert(key, cache_item)
# For successful addition of item with dependency
# Update or remove the keys
# Verify if dependent key is present
Add Key Dependency to Existing Cache Item
NCache also provides you with the ease of adding key dependency to an item already present in cache, without re-inserting it into the cache.
This is done through CacheItemAttribute
class, which has the property of Dependency
to be set against CacheItem
.
The attribute is then set against the existing key of the item, using the UpdateAttributes
method of Cache
class.
The following example shows that an order as well as a customer is already present in the cache without dependency and dependency is added on the order using UpdateAttributes
such that if the customer is updated or removed in the cache, the order is automatically removed.
// Pre-condition: Both the items already exist in cache
string customerKey = "Customer: ALFKI";
string orderKey = "Order: 1001";
// Create a key dependency where order is dependent on customer
var dependency = new KeyDependency(customerKey);
// Create a CacheItemAttribute for dependency
var attr = new CacheItemAttributes();
attr.Dependency = dependency;
// Set the attribute of dependency against the order
cache.UpdateAttributes(orderKey, attr);
// Monitor/Verify dependency through either:
// PerfMon Counters or cache API
// Precondition: Both items already exist in the cache
String customerKey = "Customer: ALFKI";
String orderKey = "Order: 1001";
// Create a key dependency where order is dependent on customer
KeyDependency dependency = new KeyDependency(customerKey);
// Create a CacheItemAttribute for dependency
CacheItemAttributes attributes = new CacheItemAttributes();
attributes.setDependency(dependency);
// Set the attribute of dependency against the order
cache.updateAttributes(orderKey, attributes);
// Verify dependency through PerfMon counters or API
// Precondition: Both items already exist in the cache
val customerKey = "Customer: ALFKI"
val orderKey = "Order: 1001"
// Create a key dependency where order is dependent on customer
val dependency = KeyDependency(customerKey)
// Create a CacheItemAttribute for dependency
val attributes = new CacheItemAttributes
attributes.setDependency(dependency)
// Set the attribute of dependency against the order
cache.updateAttributes(orderKey, attributes)
// Verify dependency through PerfMon counters or API
// This is an async method
// precondition: cache is connected
// Precondition: both the items already exist in the cache
let customerKey = "Customer: ALFKI";
let orderKey = "Order: 1001";
// create key dependency where order is dependent on customer
let dependency = new KeyDependency(customerKey);
// Create a CacheItemAttributes for dependency
let attributes = new ncache.CacheItemAttributes();
attributes.setDependency(dependency);
// Set the attributes of dependency against the order
this.cache.updateAttributes(orderKey, attributes);
// verify dependency through PerfMon counters or API
# Precondition: both the items already exist in the cache
customer_key = "Customer:ALFKI"
order_key = "Order:1001"
# Create key dependency where order is dependent on customer
dependency = ncache.KeyDependency(customer_key)
# Create a CacheItemAttributes for dependency
attributes = ncache.CacheItemAttributes()
attributes.set_dependency(dependency)
# Set the attributes of dependency against the order
cache.update_attributes(order_key, attributes)
# Verify dependency through PerfMon counters or API
Additional Resources
NCache provides sample application for Key Dependency on GitHub.
See also
Multi Cache Key Dependency
Aggregate Dependency
Data Expiration
Cache Data Dependency on External Source