SQL Dependency [Deprecated]
SQL Dependency is a deprecated mechanism in NCache used to synchronize distributed cache data with Microsoft SQL Server (2005+). Essentially, by utilizing SQL Server's Service Broker event notifications, NCache automatically invalidates and removes any stale cache items whenever the corresponding entities in the database change. This ensures data integrity by keeping the cache fresh. You can refer to the [Cache Startup Loader and Refresher] to maintain data integrity and benefit from a lack population related performance costs.
Environment Setup and Prerequisites for SQL Dependency
- Install either of the following NuGet packages in your .NET client application:
- Enterprise:
Install-Package Alachisoft.NCache.SDK -Version 4.9.1.0
- Create a new Console Application.
- Make sure that the data being added is serializable.
- Add NCache References by locating
%NCHOME%\NCache\bin\assembly\4.0 and adding Alachisoft.NCache.Web and Alachisoft.NCache.Runtime as appropriate.
- Include the
Alachisoft.NCache.Runtime.Dependencies namespace in your application.
- To learn more about the NCache Legacy API, please download the NCache 4.9 documents available as a .zip file on the Alachisoft Website.
Implementing SQL Query-Based Dependency
To add data in the cache using the SQL Dependency, NCache provides the SqlCacheDependency class. This adds items to the cache with SQL Dependency. In the following example, each item is assigned an SQL dependency and then added to the cache using the Add method.
// Precondition: Cache is already connected
// Creating connection string to get connected with database
string connectionString = "your_connection_string_here";
// Getting products from database
List<Product> products = FetchProductFromDB();
foreach (Product product in products)
{
string productKey = $"Product: {product.ProductID}";
// Creating an SQL dependency on the UnitPrice of product. Whenever the UnitPrice changes, the product is removed from the cache
string query = $"SELECT UnitPrice FROM dbo.Products WHERE ProductID = {product.ProductID}";
// Creating dependency
SqlCacheDependency dependency = new SqlCacheDependency(connectionString, query);
CacheItem productItem = new CacheItem(product);
// Adding Dependency to product item
productItem.Dependency = dependency;
// Adding CacheItem in cache
_cache.Add(productKey, productItem);
}
// Precondition: Cache is already connected
// Creating connection spring to get connected with database
String connectionString = "your_connection_string_here";
// Getting products from the database
List<Product> products = FetchProductFromDB();
for (Product product : products)
{
String productKey = "Product:" + product.getProductID();
// Creating an SQL dependency on the UnitPrice of the product. Whenever the UnitPrice changes, the product is removed from the cache
String query = "SELECT UnitPrice FROM dbo.Products WHERE ProductID = " + product.getProductID();
// Creating a dependency
SqlCacheDependency dependency = new SqlCacheDependency(connectionString, query);
CacheItem productItem = new CacheItem(product);
// Adding Dependency to the product item
productItem.setDependency(dependency);
// Adding CacheItem in cache
cache.add(productKey, productItem);
}
# Precondition: Cache is already connected
# Creating connection string to get connected with database
conn_string = "your_connection_string_here"
# Getting products from database
products = fetch_products_from_db()
for product in products:
product_key = f"Product:{product.get_product_id()}"
# Creating an SQL dependency on the UnitPrice of product. Whenever the UnitPrice changes, the product is removed from the cache
query = f"SELECT UnitPrice FROM dbo.Products WHERE ProductID = {product.get_product_id()}"
# Creating dependency
sql_dependency = SqlCacheDependency(conn_string, query)
# Creating cache item and adding dependency
cache_item = CacheItem(product)
cache_item.set_dependency(sql_dependency)
# Adding CacheItem to cache
cache.insert(product_key, cache_item)
// Precondition: Cache is already connected
// This is an async method
// Creating connection string to get connected with database
const ConnectionString = "your_connection_string_here";
// Getting products from database
const products = await fetchProductsFromDB();
for (let product of products)
{
const productKey = `Product:${product.ProductID}`;
// Creating an SQL dependency on the UnitPrice of product.
const query = `SELECT UnitPrice FROM dbo.Products WHERE ProductID = ${product.ProductID}`;
// Creating dependency
const dependency = new ncache.SqlCacheDependency(ConnectionString, query);
const cacheItem = new ncache.CacheItem(JSON.stringify(product));
// Adding Dependency to product item
cacheItem.setDependency(dependency);
// Adding CacheItem to cache
await cache.insert(productKey, cacheItem);
}
// Using NCache Enterprise 4.9.1
// Precondition: Cache is already connected
// Creating connection string to get connected with database
string connectionString = "your_connection_string_here";
// Getting products from database
List<Product> products = FetchProductFromDB();
foreach (Product product in products)
{
string productKey = $"Product: {product.ProductID}";
// Creating an SQL dependency on the UnitPrice of product. Whenever the UnitPrice changes, the product is removed from the cache
string query = $"SELECT UnitPrice FROM dbo.Products WHERE ProductID = {product.ProductID}";
// Creating dependency
SqlCacheDependency sqlDependency = new SqlCacheDependency(connectionString, query);
// Adding products with SqlCacheDependency
cache.Insert(productKey, product, sqlDependency, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal);
}
Note
To ensure the operation is fail-safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
Implementing Stored Procedure-Based Dependency
NCache lets you provide an SQL Dependency on an item using a stored procedure. You can also specify the parameters to be passed along with this procedure using the SqlCacheDependency method. The following example uses the AddBulk method to insert multiple items at once, each with its own SQL dependency.
// Precondition: Cache is already connected
// Creating connection string to get connected with database
string connectionString = "your_connection_string_here";
string spGetUnitPriceByProductID = "sp_GetUnitPriceByProductID";
// Getting products from database
List<Product> products = FetchProductFromDB();
// Creating dictionary of CacheItems
Dictionary<string, CacheItem> cacheItems = new Dictionary<string, CacheItem>();
foreach (Product product in products)
{
string productKey = $"Product: {product.ProductID}";
// Creating Param to be passed in stored procedure dictionary
SqlCmdParams paramProductID = new SqlCmdParams
{
Type = CmdParamsType.Int,
Value = product.ProductID
};
// Creating stored procedure params
Dictionary<string, SqlCmdParams> parameters = new Dictionary<string, SqlCmdParams>();
parameters.Add("@ProductID", paramProductID);
CacheItem productItem = new CacheItem(product);
// Creating an SQL dependency on the UnitPrice of product. Whenever the UnitPrice changes, the product is removed from the cache
SqlCacheDependency dependency = new SqlCacheDependency(connectionString, spGetUnitPriceByProductID, SqlCommandType.StoredProcedure, parameters);
// Adding Dependency to product item
productItem.Dependency = dependency;
cacheItems.Add(productKey, productItem);
}
// Adding CacheItems in cache
_cache.AddBulk(cacheItems);
// Precondition: Cache is already connected
// Creating connection string to get connected with database
String connectionString = "your_connection_string_here";
String spGetUnitPriceByProductID = "sp_GetUnitPriceByProductID";
// Getting products from database
List<Product> products = FetchProductFromDB();
// Create a map to store CacheItems
Map<String, CacheItem> cacheItems = new HashMap<>();
for (Product product : products)
{
String productKey = "Product:" + product.getProductID();
// Creating Param to be passed in the stored procedure dictionary
SqlCmdParams paramProductID = new SqlCmdParams();
paramProductID.setCmdParamsType(CmdParamsType.Int);
paramProductID.setValue(product.getProductID());
// Creating stored procedure params
Map<String, SqlCmdParams> parameters = new HashMap<>();
parameters.put("@ProductID", paramProductID);
CacheItem productItem = new CacheItem(product);
// Creating an SQL dependency on the UnitPrice of the product. Whenever the UnitPrice changes, the product is removed from the cache
SqlCacheDependency dependency = new SqlCacheDependency(connectionString, spGetUnitPriceByProductID, SqlCommandType.StoredProcedure, parameters);
// Adding Dependency to the product item
productItem.setDependency(dependency);
cacheItems.put(productKey, productItem);
System.out.println("Added product to cache items: " + productKey);
}
// Adding CacheItems in cache using addBulk method
cache.addBulk(cacheItems);
# Precondition: Cache is already connected
# Creating a connection string to establish connection with the database
conn_string = "your_connection_string_here"
# Name of the stored procedure item is dependent upon
stored_proc_name = "GetCustomerByID"
# Specify the customerID passed as parameters
sql_cmd_params = {"CustomerID": "ALFKI"}
# Create sql dependency
# In case the stored procedure has no parameters, pass null as the SqlCmdParams value
sql_cache_dependency = ncache.SqlCacheDependency(conn_string, stored_proc_name, ncache.SqlCommandType.STORED_PROCEDURE, sql_cmd_params)
# Get orders from database against customerId
orders = fetch_orders_by_customer_id("ALFKI")
for order in orders:
# Generate a unique cache key for this order
key = "Order:" + order.get_order_id()
# Create a new cache item and add sql dependency to it
item = ncache.CacheItem(order)
item.set_dependency(sql_cache_dependency)
# Add cache item in the cache with sql dependency
cache.insert(key, item)
# For successful addition of item with SQL Dependency
# Update the record in the database and check if key is present
// Precondition: Cache is already connected
// Creating connection string to get connected with database
const connectionString = "your_connection_string_here";
const spGetUnitPriceByProductID = "sp_GetUnitPriceByProductID";
// Getting products from database
const products = await fetchProductsFromDB();
const cacheItems = new Map();
for (let product of products)
{
const productKey = `Product:${product.ProductID}`;
const parameters = new Map();
var cmdParams = new ncache.SqlCmdParams();
cmdParams.setValue(123);
cmdParams.setCmdParamsType(ncache.CmdParamsType.Int);
cmdParams.setSqlParameterDirection(ncache.SqlParamDirection.Input);
parameters.set("@ProductID", cmdParams);
const productItem = new ncache.CacheItem(JSON.stringify(product));
// Creating an SQL dependency on the UnitPrice of product. Whenever the UnitPrice changes, the product is removed from the cache
const dependency = new ncache.SqlCacheDependency(
connectionString,
spGetUnitPriceByProductID,
ncache.SqlCommandType.StoredProcedure,
parameters
);
productItem.setDependency(dependency);
// Adding Dependency to product item
cacheItems.set(productKey, productItem);
}
// Adding CacheItems in cache
await cache.insertBulk(cacheItems);
Important
- In an environment where the user has more restricted access to the database, users are supposed to create SQL Service and Queue per NCache process by enabling the Custom SQL Notification Mode in the Options tab in the NCache Management Center.
- You can also create the required SQL Service and Queue using the script NCacheServiceQueue.sql located at %NCHOME%\bin\resources.
Additional Resources
NCache provides a sample application for SQL dependency on GitHub.
See Also
.NET: Alachisoft.NCache.Runtime.Dependencies namespace.
Java: com.alachisoft.ncache.runtime.dependencies namespace.
Python: ncache.runtime.dependencies class.
Node.js: SqlCacheDependency class.