diff --git a/playground/dotnetcore/BasicCacheOperations/Code/BasicCacheOperations.csproj b/playground/dotnetcore/BasicCacheOperations/Code/BasicCacheOperations.csproj new file mode 100644 index 0000000..b5d78fd --- /dev/null +++ b/playground/dotnetcore/BasicCacheOperations/Code/BasicCacheOperations.csproj @@ -0,0 +1,28 @@ + + + Exe + net6.0 + enable + enable + bin\ + false + false + Exe + + + + + + + + Always + + + Always + + + Always + + + + diff --git a/playground/dotnetcore/BasicCacheOperations/Code/Program.cs b/playground/dotnetcore/BasicCacheOperations/Code/Program.cs new file mode 100644 index 0000000..dea1e67 --- /dev/null +++ b/playground/dotnetcore/BasicCacheOperations/Code/Program.cs @@ -0,0 +1,75 @@ +using Alachisoft.NCache.Client; +using Alachisoft.NCache.Runtime.Caching; + +namespace NCache.Playground.Samples.BasicCacheOperations +{ + // Basic caching operations (CRUD) as an intro to NCache API + + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Sample showing basic caching operations (CRUD) in NCache, along with expiration.\n"); + + string cacheName = args[0]; + + Console.WriteLine($"Connecting to cache: {cacheName}\n"); + // Connect to the cache and return a cache handle + var cache = CacheManager.GetCache(cacheName); + Console.WriteLine($"Connected to Cache successfully: {cacheName}\n"); + + // Add product 10001 to the cache with a 5-min expiration + Product prod1 = new Product { ProductID = 10001, Name = "Laptop", Price = 1000, Category = "Electronics" }; + + string prod1Key = prod1.ProductID.ToString(); + var productCacheItem = new CacheItem(prod1); + productCacheItem.Expiration = new Expiration(ExpirationType.Absolute, TimeSpan.FromMinutes(5)); + + // Add to the cache with 5min absolute expiration (TTL). Item expires automatically + cache.Add(prod1Key, productCacheItem); + + Console.WriteLine("Product 10001 added successfully (5min expiration):"); + PrintProductDetails(prod1); + + // Get from the cache. If not found, a null is returned + Product retrievedprod1 = cache.Get(prod1Key); + if (retrievedprod1 != null) + { + Console.WriteLine("Product 10001 retrieved successfully:"); + PrintProductDetails(retrievedprod1); + } + + retrievedprod1.Price = 3000; + + // Update product in the cache. If not found, it is added + productCacheItem = new CacheItem(retrievedprod1); + productCacheItem.Expiration = new Expiration(ExpirationType.Absolute, TimeSpan.FromMinutes(5)); + cache.Insert(prod1Key, productCacheItem); + + Console.WriteLine("Price for Product 10001 updated successfully:"); + PrintProductDetails(retrievedprod1); + + // Remove the item from the cache + cache.Remove(prod1Key); + Console.WriteLine($"Deleted the product {prod1Key} from the cache...\n"); + + Console.WriteLine("Sample completed successfully."); + } + + private static void PrintProductDetails(Product product) + { + Console.WriteLine("ProductID, Name, Price, Category"); + Console.WriteLine($"- {product.ProductID}, {product.Name}, {product.Price}, {product.Category} \n"); + } + } + + // Sample class for Product + [Serializable] + public class Product + { + public int ProductID { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + public string Category { get; set; } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/BasicCacheOperations/Code/Properties/launchSettings.json b/playground/dotnetcore/BasicCacheOperations/Code/Properties/launchSettings.json new file mode 100644 index 0000000..caf17bf --- /dev/null +++ b/playground/dotnetcore/BasicCacheOperations/Code/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "BasicCacheOperations": { + "commandName": "Project", + "commandLineArgs": "demoCache" + } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/CacheItemLocking/Code/CacheItemLocking.csproj b/playground/dotnetcore/CacheItemLocking/Code/CacheItemLocking.csproj new file mode 100644 index 0000000..3c2c35f --- /dev/null +++ b/playground/dotnetcore/CacheItemLocking/Code/CacheItemLocking.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + bin\ + false + false + Exe + + + + + + + diff --git a/playground/dotnetcore/CacheItemLocking/Code/Program.cs b/playground/dotnetcore/CacheItemLocking/Code/Program.cs new file mode 100644 index 0000000..cb13975 --- /dev/null +++ b/playground/dotnetcore/CacheItemLocking/Code/Program.cs @@ -0,0 +1,72 @@ +using Alachisoft.NCache.Client; + +namespace NCache.Playground.Samples.CacheItemLocking +{ + // Locking an item prevents other users from accessing it while you update it. + // You can lock with cache.GetCacheItem() or cache.Lock() and unlock with cache.Insert() or cache.Unlock() + // NOTE: Locking API is for application level locking. NCache already has its own internal locking + // for concurrency and thread-safe operations. + + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Sample showing item level lock and unlock in NCache.\n"); + string cacheName = args[0]; + + Console.WriteLine($"Connecting to cache: {cacheName}\n"); + // Connect to the cache and return a cache handle + var cache = CacheManager.GetCache(cacheName); + Console.WriteLine($"Connected to Cache successfully: {cacheName}\n"); + + Product prod1 = new Product { ProductID = 11001, Name = "Laptop", Price = 1000, Category = "Electronics" }; + + string prod1Key = prod1.ProductID.ToString(); + Console.WriteLine("Adding product 11001 to the cache..."); + + // add a product to the cache. if it already exists, the operation will fail + cache.Insert(prod1Key, prod1); + Console.WriteLine("Product added successfully:"); + PrintProductDetails(prod1); + + // Get product 11001 and lock it in the cache + Console.WriteLine("Get and lock product 11001 in the cache..."); + LockHandle lockHandle = null; + + // Passing "acquireLock:" flag also locks the item and "lockTimeout:" releases the lock after 10sec + var lockedCacheItem = cache.GetCacheItem(prod1Key, acquireLock: true, lockTimeout: TimeSpan.FromSeconds(10), ref lockHandle); + if (lockedCacheItem != null) + { + Console.WriteLine("Product 11001 retrieved and locked successfully:"); + var retrievedProduct = lockedCacheItem.GetValue(); + PrintProductDetails(retrievedProduct); + + // Change the price of product 11001 + retrievedProduct.Price = 2000; + + // Insert() updates the item and releases the lock + cache.Insert(prod1Key, lockedCacheItem, lockHandle, releaseLock: true); + Console.WriteLine("Updated price of product 11001 and released the lock simultaneously in the cache..."); + + PrintProductDetails(retrievedProduct); + } + Console.WriteLine("Sample completed successfully."); + } + + private static void PrintProductDetails(Product product) + { + Console.WriteLine("ProductID, Name, Price, Category"); + Console.WriteLine($"- {product.ProductID}, {product.Name}, {product.Price}, {product.Category} \n"); + } + } + + // Sample class for Product + [Serializable] + public class Product + { + public int ProductID { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + public string Category { get; set; } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/CacheItemLocking/Code/Properties/launchSettings.json b/playground/dotnetcore/CacheItemLocking/Code/Properties/launchSettings.json new file mode 100644 index 0000000..1375199 --- /dev/null +++ b/playground/dotnetcore/CacheItemLocking/Code/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "CacheItemLocking": { + "commandName": "Project", + "commandLineArgs": "demoCache" + } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/DataStructures/Code/DataStructures.csproj b/playground/dotnetcore/DataStructures/Code/DataStructures.csproj new file mode 100644 index 0000000..3c2c35f --- /dev/null +++ b/playground/dotnetcore/DataStructures/Code/DataStructures.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + bin\ + false + false + Exe + + + + + + + diff --git a/playground/dotnetcore/DataStructures/Code/Program.cs b/playground/dotnetcore/DataStructures/Code/Program.cs new file mode 100644 index 0000000..53cfd70 --- /dev/null +++ b/playground/dotnetcore/DataStructures/Code/Program.cs @@ -0,0 +1,129 @@ +using Alachisoft.NCache.Client; +using Alachisoft.NCache.Client.DataTypes.Collections; + +namespace NCache.Playground.Samples.DataStructures +{ + // Use NCache distributed data structures (List and Queue in this sample). NCache provides + // Set, Dictionary, and Counter data structures as well. These data structures are distributed in the cluster + // for scalability and accessible to all clients. + + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Sample showing distributed data structures in NCache (List, Queue) for more powerful data management.\n"); + + var cacheName = args[0]; + + Console.WriteLine($"Connecting to cache: {cacheName}\n"); + // Connect to the cache and return a cache handle + var cache = CacheManager.GetCache(cacheName); + Console.WriteLine($"Connected to Cache successfully: {cacheName}\n"); + + Console.WriteLine("Create a List data structure and add products 'Electronics' to it..."); + + // Get the list if it already exists in the cache + IDistributedList productList = cache.DataTypeManager.GetList("productList"); + + if (productList == null) + { + // Create a List data structure in the cache and then add products to it + productList = cache.DataTypeManager.CreateList("productList"); + } + + // These products are directly added to the cache inside the List data structure when you add them below + productList.Add(new Product { ProductID = 15001, Name = "Laptop", Price = 2000, Category = "Electronics" }); + productList.Add(new Product { ProductID = 15002, Name = "Kindle", Price = 1000, Category = "Electronics" }); + productList.Add(new Product { ProductID = 15004, Name = "Smart Phone", Price = 1000, Category = "Electronics" }); + productList.Add(new Product { ProductID = 15005, Name = "Mobile Phone", Price = 200, Category = "Electronics" }); + + PrintProductList(productList); + + Console.WriteLine("Create a Queue data structure and add orders to it..."); + + // Get the queue if it already exists in the cache + IDistributedQueue orderQueue = cache.DataTypeManager.GetQueue("orderQueue"); + + if (orderQueue == null) + { + // Create a Queue data structure and then add orders to it by maintaining their sequence + orderQueue = cache.DataTypeManager.CreateQueue("orderQueue"); + } + + // These orders are directly added to the cache inside the Queue data structure when you enqueue them below + orderQueue.Enqueue(new Order { OrderID = 16248, Customer = "Vins et alcools Chevalier", OrderDate = new DateTime(1997, 7, 4), ShipVia = "Federal Shipping" }); + orderQueue.Enqueue(new Order { OrderID = 16249, Customer = "Toms Spezialitäten", OrderDate = new DateTime(1997, 7, 5), ShipVia = "Speedy Express" }); + orderQueue.Enqueue(new Order { OrderID = 16250, Customer = "Hanari Carnes", OrderDate = new DateTime(1997, 7, 7), ShipVia = "United Package" }); + orderQueue.Enqueue(new Order { OrderID = 16251, Customer = "Victuailles en stock", OrderDate = new DateTime(1997, 7, 8), ShipVia = "Speedy Express" }); + + PrintOrderQueue(orderQueue); + + Console.WriteLine("Fetch the list and print all items from the List data structure..."); + + // Fetch the List data structure from the cache and then access all items in it + var fetchedProductList = cache.DataTypeManager.GetList("productList"); + + PrintProductList(fetchedProductList); + + Console.WriteLine("Process all orders from the Queue one by one in a sequence\n"); + + // Fetch the Queue data structure from the cache and then process all orders one by one in a sequence + var fetchedOrderQueue = cache.DataTypeManager.GetQueue("orderQueue"); + while (fetchedOrderQueue.Count > 0) + { + var order = orderQueue.Dequeue(); + Console.WriteLine("Process order : " + order.OrderID); + PrintOrder(order); + } + + // Removing all items from the list + productList.RemoveRange(0, productList.Count); + + Console.WriteLine("Removed products from the List data structure.\n"); + + Console.WriteLine("Sample completed successfully."); + } + + static void PrintProductList(IList productList) + { + Console.WriteLine("ProductID, Name, Price, Category, Tags"); + foreach (var product in productList) + { + Console.WriteLine($"- {product.ProductID}, {product.Name}, ${product.Price}, {product.Category}"); + } + Console.WriteLine(); + } + + static void PrintOrderQueue(IDistributedQueue orderQueue) + { + Console.WriteLine("OrderID, Customer, Order Date, Ship Via"); + foreach (var order in orderQueue) + { + Console.WriteLine($"- {order.OrderID}, {order.Customer}, {order.OrderDate.ToShortDateString()}, {order.ShipVia}"); + } + Console.WriteLine(); + } + + static void PrintOrder(Order order) + { + Console.WriteLine("OrderID, Customer, Order Date, Ship Via"); + Console.WriteLine($"- {order.OrderID}, {order.Customer}, {order.OrderDate.ToShortDateString()}, {order.ShipVia} \n"); + } + } + + class Product + { + public int ProductID { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + public string Category { get; set; } + } + + class Order + { + public int OrderID { get; set; } + public string Customer { get; set; } + public DateTime OrderDate { get; set; } + public string ShipVia { get; set; } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/DataStructures/Code/Properties/launchSettings.json b/playground/dotnetcore/DataStructures/Code/Properties/launchSettings.json new file mode 100644 index 0000000..afa6463 --- /dev/null +++ b/playground/dotnetcore/DataStructures/Code/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "DataStructures": { + "commandName": "Project", + "commandLineArgs": "demoCache" + } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/EFCoreLinqCacheLookup/Code/EfCoreLinqCacheLookup.csproj b/playground/dotnetcore/EFCoreLinqCacheLookup/Code/EfCoreLinqCacheLookup.csproj new file mode 100644 index 0000000..38e4829 --- /dev/null +++ b/playground/dotnetcore/EFCoreLinqCacheLookup/Code/EfCoreLinqCacheLookup.csproj @@ -0,0 +1,31 @@ + + + + Exe + net6.0 + enable + enable + bin\ + false + false + Exe + + + + + + + + + + Always + + + Always + + + Always + + + + diff --git a/playground/dotnetcore/EFCoreLinqCacheLookup/Code/Program.cs b/playground/dotnetcore/EFCoreLinqCacheLookup/Code/Program.cs new file mode 100644 index 0000000..e32dce7 --- /dev/null +++ b/playground/dotnetcore/EFCoreLinqCacheLookup/Code/Program.cs @@ -0,0 +1,119 @@ +using Alachisoft.NCache.EntityFrameworkCore; +using Alachisoft.NCache.Runtime.Caching; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; + +namespace NCache.Playground.Samples.EFCoreCacheLookup +{ + // Use NCache integration with EF Core (thru Extension Methods) to load reference data into the cache + // and later search the cache thru EF Core LINQ queries. This is not resultset caching. + // We're using an SQLite in-memory database (with "Code First" approach) that goes away when the process ends. + + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Sample showing NCache EF Core Extension Methods to load data in the cache and then use LINQ to query for it.\n"); + + using (var dbContext = new ProductsDbContext(args[0])) + { + dbContext.Database.EnsureCreated(); + + Console.WriteLine("LoadIntoCache: Adding all products to the cache thru EF Core Extension Method..."); + + // Cache each object separately + var cachingOptions = new CachingOptions() { StoreAs = StoreAs.SeperateEntities }; + + // This method should use LINQ to load all products. Currently, it is using EF Core mapping to the Product table + // We need to show how to use LINQ here even though all products will be loaded + // p => true is a simple expression that returns true for every element in the collection. + var products = dbContext.Products.Where(p => true).LoadIntoCache(cachingOptions).ToList(); + + PrintProducts(products); + + Console.WriteLine("Find products with Category IN (\"Electronics\", \"Stationery\") AND price < $2000"); + + // Creating an array of categories for filtering products + var categoryFilter = new[] { "Electronics", "Stationery" }; + + var fetchedProducts = dbContext.Products + .Where(p => categoryFilter.Contains(p.Category) && p.Price < 2000) + .FromCacheOnly() + .ToList(); + + PrintProducts(fetchedProducts); + + Console.WriteLine("Find all \"phone\" products (using LIKE operator) AND (Category = \"Electronics\" OR Category = \"Stationery\")"); + var keyword = "Phone"; + fetchedProducts = dbContext.Products + .Where(p => p.Name.Contains(keyword) && (p.Category == "Electronics" || p.Category == "Stationery")) + .FromCacheOnly() + .ToList(); + + PrintProducts(fetchedProducts); + + Console.WriteLine("Sample completed successfully."); + } + } + + static void PrintProducts(List products) + { + Console.WriteLine("ProductID, Name, Price, Category"); + foreach (var product in products) + { + Console.WriteLine($"- {product.ProductID}, {product.Name}, ${product.Price}, {product.Category}"); + } + + Console.WriteLine(); + } + } + + public class ProductsDbContext : DbContext + { + public string _cacheName; + public DbSet Products { get; set; } + + public ProductsDbContext(string cacheName) + { + _cacheName = cacheName; + } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + string cacheId = _cacheName; + + Console.WriteLine($"Connecting to cache: {cacheId}\n"); + NCacheConfiguration.Configure(cacheId, DependencyType.Other); + Console.WriteLine($"Connected to Cache successfully: {cacheId}\n"); + + // Configure in-memory database using SQLite provider + var connection = new SqliteConnection("Data Source=:memory:"); + connection.Open(); + optionsBuilder.UseSqlite(connection); + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasData( + new Product { ProductID = 14001, Name = "Laptop", Price = 2000, Category = "Electronics" }, + new Product { ProductID = 14002, Name = "Kindle", Price = 1000, Category = "Electronics" }, + new Product { ProductID = 14003, Name = "Book", Price = 100, Category = "Stationery" }, + new Product { ProductID = 14004, Name = "Smart Phone", Price = 1000, Category = "Electronics" }, + new Product { ProductID = 14005, Name = "Mobile Phone", Price = 200, Category = "Electronics" } + ); + } + } + + [Serializable] + public class Product + { + public int ProductID { get; set; } + + [QueryIndexed] + public string Name { get; set; } + [QueryIndexed] + public int Price { get; set; } + [QueryIndexed] + public string Category { get; set; } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/EFCoreLinqCacheLookup/Code/Properties/launchSettings.json b/playground/dotnetcore/EFCoreLinqCacheLookup/Code/Properties/launchSettings.json new file mode 100644 index 0000000..50a379a --- /dev/null +++ b/playground/dotnetcore/EFCoreLinqCacheLookup/Code/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "EfCoreLinqCacheLookup": { + "commandName": "Project", + "commandLineArgs": "demoCache" + } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/EFCoreResultsetCaching/Code/EfCoreResultsetCaching.csproj b/playground/dotnetcore/EFCoreResultsetCaching/Code/EfCoreResultsetCaching.csproj new file mode 100644 index 0000000..5258d49 --- /dev/null +++ b/playground/dotnetcore/EFCoreResultsetCaching/Code/EfCoreResultsetCaching.csproj @@ -0,0 +1,33 @@ + + + + Exe + net6.0 + enable + enable + bin\ + false + false + Exe + + + + + + + + + + + + Always + + + Always + + + Always + + + + diff --git a/playground/dotnetcore/EFCoreResultsetCaching/Code/Program.cs b/playground/dotnetcore/EFCoreResultsetCaching/Code/Program.cs new file mode 100644 index 0000000..4e67389 --- /dev/null +++ b/playground/dotnetcore/EFCoreResultsetCaching/Code/Program.cs @@ -0,0 +1,106 @@ +using Alachisoft.NCache.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.Sqlite; + +namespace NCache.Playground.Samples.EFCoreResultsetCaching +{ + // Use NCache integration with EF Core (thru Extension Methods) to seamlessly cache EF Core query resultset. + // Next time, EF Core fetches the resultset from the cache and saves an expensive database trip. + // We're using an SQLite in-memory database (with "Code First" approach) that goes away when the process ends. + + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Sample showing EF Core Resultset caching with NCache to save expensive database trips.\n"); + + using (var dbContext = new CustomersbContext(args[0])) + { + dbContext.Database.EnsureCreated(); + dbContext.Database.Migrate(); + + // Cache the entire query resultset as one item in the cache + var cachingOptionsAlfki = new CachingOptions { StoreAs = StoreAs.Collection }; + cachingOptionsAlfki.SetAbsoluteExpiration(DateTime.Now.AddMinutes(5)); + + // .FromCache() Extension Method fetches the resultset from the cache. If not found, + // it caches it automatically. We are caching with 5min expiration. + + // This is the first call so resultset is obtained from the database + var alFKICustomer = dbContext.Customers.Where(c => c.CustomerID == "ALFKI") + .FromCache(cachingOptionsAlfki).FirstOrDefault(); + + Console.WriteLine("Loaded customer ALFKI from the database and cached...5min expiration"); + + if (alFKICustomer != null) + PrintCustomerDetails(alFKICustomer); + + // This is the second call to .FromCache() so resultset is fetched from the cache + alFKICustomer = dbContext.Customers.Where(c => c.CustomerID == "ALFKI") + .FromCache(cachingOptionsAlfki).FirstOrDefault(); + + if (alFKICustomer != null) + { + Console.WriteLine("Found and retrieved customer ALFKI from the cache..."); + PrintCustomerDetails(alFKICustomer); + } + + Console.WriteLine("Sample completed successfully."); + } + } + + static void PrintCustomerDetails(Customer customer) + { + if (customer != null) + { + Console.WriteLine("CustomerID, Company, City, Country"); + Console.WriteLine($"- {customer.CustomerID}, {customer.CompanyName}, {customer.City}, {customer.Country}"); + } + Console.WriteLine(); + } + } + + public class CustomersbContext : DbContext + { + public string _cacheName; + public DbSet Customers { get; set; } + + public CustomersbContext(string cacheName) + { + _cacheName = cacheName; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + string cacheId = _cacheName; + + Console.WriteLine($"Connecting to cache: {cacheId}\n"); + NCacheConfiguration.Configure(cacheId, DependencyType.Other); + Console.WriteLine($"Connected to Cache successfully: {cacheId}\n"); + + // Configure in-memory database using SQLite provider + var connection = new SqliteConnection("Data Source=:memory:"); + connection.Open(); + optionsBuilder.UseSqlite(connection); + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + // Seed dummy data for demonstration purposes + modelBuilder.Entity().HasData( + new Customer { CustomerID = "ALFKI", CompanyName = "Alfreds Futterkiste", City = "Berlin", Country = "Germany" }, + new Customer { CustomerID = "GREAL", CompanyName = "Great Lakes Food Market", City = "Eugene", Country = "USA" } + ); + } + } + + [Serializable] + public class Customer + { + public string CustomerID { get; set; } + public string CompanyName { get; set; } + public string City { get; set; } + public string Country { get; set; } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/EFCoreResultsetCaching/Code/Properties/launchSettings.json b/playground/dotnetcore/EFCoreResultsetCaching/Code/Properties/launchSettings.json new file mode 100644 index 0000000..5264d1e --- /dev/null +++ b/playground/dotnetcore/EFCoreResultsetCaching/Code/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "EfCoreResultsetCaching": { + "commandName": "Project", + "commandLineArgs": "demoCache" + } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/GroupingCachedData/Code/GroupingCachedData.csproj b/playground/dotnetcore/GroupingCachedData/Code/GroupingCachedData.csproj new file mode 100644 index 0000000..3c2c35f --- /dev/null +++ b/playground/dotnetcore/GroupingCachedData/Code/GroupingCachedData.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + bin\ + false + false + Exe + + + + + + + diff --git a/playground/dotnetcore/GroupingCachedData/Code/Program.cs b/playground/dotnetcore/GroupingCachedData/Code/Program.cs new file mode 100644 index 0000000..3c7da62 --- /dev/null +++ b/playground/dotnetcore/GroupingCachedData/Code/Program.cs @@ -0,0 +1,98 @@ +using Alachisoft.NCache.Client; +using Alachisoft.NCache.Runtime.Caching; + +namespace NCache.Playground.Samples.GroupingCachedData +{ + // Use the Tags feature of NCache to group items. First, use Tags while adding to the cache. Later, fetch by Tags + + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Sample showing the Tags feature of NCache to logically group related data to easily fetch later.\n"); + + // Connect to the cache + string cacheName = args[0]; + + Console.WriteLine($"Connecting to cache: {cacheName}"); + // Connect to the cache and return a cache handle + var cache = CacheManager.GetCache(cacheName); + Console.WriteLine($"Cache connected successfully: {cacheName}\n"); + + var laptop = new Product { ProductID = 12001, Name = "Laptop", Price = 2000, Category = "Electronics" }; + var kindle = new Product { ProductID = 12002, Name = "Kindle", Price = 1000, Category = "Electronics" }; + var book = new Product { ProductID = 12003, Name = "Book", Price = 100, Category = "Stationery" }; + var smartPhone = new Product { ProductID = 12004, Name = "Smart Phone", Price = 1000, Category = "Electronics" }; + var mobilePhone = new Product { ProductID = 12005, Name = "Mobile Phone", Price = 200, Category = "Electronics" }; + + var laptopCacheItem = new CacheItem(laptop) { Tags = new[] { new Tag("Technology"), new Tag("Gadgets") } }; + var kindleCacheItem = new CacheItem(kindle) { Tags = new[] { new Tag("Technology"), new Tag("Reading") } }; + var bookCacheItem = new CacheItem(book) { Tags = new[] { new Tag("Education"), new Tag("Reading") } }; + var smartPhoneCacheItem = new CacheItem(smartPhone) { Tags = new[] { new Tag("Technology"), new Tag("Communication") } }; + var mobilePhoneCacheItem = new CacheItem(mobilePhone) { Tags = new[] { new Tag("Technology"), new Tag("Communication") } }; + + var products = new Dictionary + { + { "12001", laptopCacheItem }, + { "12002", kindleCacheItem }, + { "12003", bookCacheItem }, + { "12004", smartPhoneCacheItem }, + { "12005", mobilePhoneCacheItem } + }; + + // Add all the products to the cache. + foreach (var product in products) + { + cache.Insert(product.Key, product.Value); + } + Console.WriteLine("Products added to the cache successfully.\n"); + + var technologyItems = cache.SearchService.GetByTag(new Tag("Technology")); + + Console.WriteLine("Got Items from the cache by Tag \"Technology\""); + PrintProductDetails(technologyItems); + + // Get all items from the cache with this Tag. readingItems is a list of key-value pairs + var readingItems = cache.SearchService.GetByTag(new Tag("Reading")); + + Console.WriteLine("Got the Items from the cache by Tag \"Reading\""); + PrintProductDetails(readingItems); + + // Create an array of tags + Tag[] tags = new[] { new Tag("Technology"), new Tag("Reading") }; + + // Remove all items from the cache with any of the tags + cache.SearchService.RemoveByTags(tags, TagSearchOptions.ByAnyTag); + Console.WriteLine("Removed Items by Tags \"Technology\" and \"Reading\"\n"); + + Console.WriteLine("Sample completed successfully."); + } + + static void PrintProductDetails(IEnumerable> items) + { + if (items != null && items.Any()) + { + Console.WriteLine("ProductID, Name, Price, Category"); + foreach (var cacheItem in items) + { + var product = cacheItem.Value; + Console.WriteLine($"- {product.ProductID}, {product.Name}, ${product.Price}, {product.Category}"); + } + } + else + { + Console.WriteLine("No items found..."); + } + Console.WriteLine(); + } + } + + [Serializable] + public class Product + { + public int ProductID { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + public string Category { get; set; } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/GroupingCachedData/Code/Properties/launchSettings.json b/playground/dotnetcore/GroupingCachedData/Code/Properties/launchSettings.json new file mode 100644 index 0000000..7274640 --- /dev/null +++ b/playground/dotnetcore/GroupingCachedData/Code/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "GroupingCachedData": { + "commandName": "Project", + "commandLineArgs": "demoCache" + } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/NCachePlaygroundSamples.sln b/playground/dotnetcore/NCachePlaygroundSamples.sln new file mode 100644 index 0000000..61b3c2f --- /dev/null +++ b/playground/dotnetcore/NCachePlaygroundSamples.sln @@ -0,0 +1,67 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32210.238 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicCacheOperations", "BasicCacheOperations\Code\BasicCacheOperations.csproj", "{3404E096-E710-4067-B824-40D5CBFA0C48}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CacheItemLocking", "CacheItemLocking\Code\CacheItemLocking.csproj", "{B78E386E-C114-4E11-8816-6ED088B7F24A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GroupingCachedData", "GroupingCachedData\Code\GroupingCachedData.csproj", "{E0A5C4E5-900E-4A46-8BB2-489A6EEBAE58}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EfCoreResultsetCaching", "EFCoreResultsetCaching\Code\EfCoreResultsetCaching.csproj", "{CAAD57B4-29FB-4D3A-91BD-64E18A985C7A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SqlQueryCacheLookup", "SqlQueryCacheLookup\Code\SqlQueryCacheLookup.csproj", "{B67C5C42-EC23-46AA-B237-BC8642560D18}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EfCoreLinqCacheLookup", "EFCoreLinqCacheLookup\Code\EfCoreLinqCacheLookup.csproj", "{C7C214BA-D588-4F0F-A449-E657266A7337}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStructures", "DataStructures\Code\DataStructures.csproj", "{8A24B984-80C4-4FCD-9F85-05C533D524EC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PubSubMessaging", "PubSubMessaging\Code\PubSubMessaging.csproj", "{581EE271-EBF6-4ECD-A4AF-9C86EC7B0162}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3404E096-E710-4067-B824-40D5CBFA0C48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3404E096-E710-4067-B824-40D5CBFA0C48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3404E096-E710-4067-B824-40D5CBFA0C48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3404E096-E710-4067-B824-40D5CBFA0C48}.Release|Any CPU.Build.0 = Release|Any CPU + {B78E386E-C114-4E11-8816-6ED088B7F24A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B78E386E-C114-4E11-8816-6ED088B7F24A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B78E386E-C114-4E11-8816-6ED088B7F24A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B78E386E-C114-4E11-8816-6ED088B7F24A}.Release|Any CPU.Build.0 = Release|Any CPU + {E0A5C4E5-900E-4A46-8BB2-489A6EEBAE58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0A5C4E5-900E-4A46-8BB2-489A6EEBAE58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0A5C4E5-900E-4A46-8BB2-489A6EEBAE58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0A5C4E5-900E-4A46-8BB2-489A6EEBAE58}.Release|Any CPU.Build.0 = Release|Any CPU + {CAAD57B4-29FB-4D3A-91BD-64E18A985C7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CAAD57B4-29FB-4D3A-91BD-64E18A985C7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAAD57B4-29FB-4D3A-91BD-64E18A985C7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CAAD57B4-29FB-4D3A-91BD-64E18A985C7A}.Release|Any CPU.Build.0 = Release|Any CPU + {B67C5C42-EC23-46AA-B237-BC8642560D18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B67C5C42-EC23-46AA-B237-BC8642560D18}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B67C5C42-EC23-46AA-B237-BC8642560D18}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B67C5C42-EC23-46AA-B237-BC8642560D18}.Release|Any CPU.Build.0 = Release|Any CPU + {C7C214BA-D588-4F0F-A449-E657266A7337}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7C214BA-D588-4F0F-A449-E657266A7337}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7C214BA-D588-4F0F-A449-E657266A7337}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7C214BA-D588-4F0F-A449-E657266A7337}.Release|Any CPU.Build.0 = Release|Any CPU + {8A24B984-80C4-4FCD-9F85-05C533D524EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A24B984-80C4-4FCD-9F85-05C533D524EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A24B984-80C4-4FCD-9F85-05C533D524EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A24B984-80C4-4FCD-9F85-05C533D524EC}.Release|Any CPU.Build.0 = Release|Any CPU + {581EE271-EBF6-4ECD-A4AF-9C86EC7B0162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {581EE271-EBF6-4ECD-A4AF-9C86EC7B0162}.Debug|Any CPU.Build.0 = Debug|Any CPU + {581EE271-EBF6-4ECD-A4AF-9C86EC7B0162}.Release|Any CPU.ActiveCfg = Release|Any CPU + {581EE271-EBF6-4ECD-A4AF-9C86EC7B0162}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {32D69342-C0D9-42E5-AD2C-689F0D099C2C} + EndGlobalSection +EndGlobal diff --git a/playground/dotnetcore/PubSubMessaging/Code/Program.cs b/playground/dotnetcore/PubSubMessaging/Code/Program.cs new file mode 100644 index 0000000..c5f2d4f --- /dev/null +++ b/playground/dotnetcore/PubSubMessaging/Code/Program.cs @@ -0,0 +1,138 @@ +using Alachisoft.NCache.Client; +using Alachisoft.NCache.Runtime.Caching; + +namespace NCache.Playground.Samples.PubSubMessaging +{ + // Use NCache Pub/Sub Messaging in this sample. In NCache, you can create multiple Topics + // and against each topic create multiple publishers and subscribers. In this sample, + // 2 parallel Async publisher tasks publish on the same topic and 2 subscribers receive + // messages from this topic. All messages use DeliveryOption. Any so only one subscriber + // gets each message. DeliveryOption.All is available but not used. + + class Program + { + static string topicName = "ORDERS"; + static readonly object consoleLock = new object(); + static async Task Main(string[] args) + { + Console.WriteLine("Sample showing NCache Pub/Sub Messaging for reliable real-time messaging between publishers and subscribers.\n"); + + var cacheName = args[0]; + + Console.WriteLine($"Connecting to cache: {cacheName}\n"); + // Connect to the cache and return a cache handle + var cache = CacheManager.GetCache(cacheName); + Console.WriteLine($"Connected to Cache successfully: {cacheName}\n"); + + Console.WriteLine($"Create a Topic {topicName} ...\n"); + + // Create a Topic in NCache. + var topic = cache.MessagingService.CreateTopic(topicName); + + Console.WriteLine("Register 2 subscribers for Topic " + topicName + "\n"); + + // Register subscribers to this Topic + var subscription1 = topic.CreateSubscription(MessageReceived_Subscription1); + var subscription2 = topic.CreateSubscription(MessageReceived_Subscription2); + + // Create first asynchronous publisher task to publish 2 messages + var publisher1Task = new Task(async () => + { + var message1 = new Message + ( + new Order() { OrderID = 17348, Customer = "Vins et alcools Chevalier", OrderDate = DateTime.Parse("04-Jul-1997"), ShipVia = "Federal Shipping" } + ); + + var message2 = new Message + ( + new Order() { OrderID = 17350, Customer = "Hanari Carnes", OrderDate = DateTime.Parse("07-Jul-1997"), ShipVia = "United Package" } + ); + + PrintMessage(message1, "Publisher 1", null); + // "Any" means that only one subscriber will receive this message + // Another option is "All" where all subscribers recieve the message + topic.Publish(message1, DeliveryOption.Any); + + // wait for 1sec before publishing again + Thread.Sleep(1000); + PrintMessage(message2, "Publisher 1", null); + + topic.Publish(message2, DeliveryOption.Any); + }); + + // Create second asynchronous publisher task to publish 2 messages + var publisher2Task = new Task(async () => + { + var message1 = new Message + ( + new Order() { OrderID = 17349, Customer = "Toms Spezialitäten", OrderDate = DateTime.Parse("05-Jul-1997"), ShipVia = "Speedy Express" } + ); + + var message2 = new Message + ( + new Order() { OrderID = 17351, Customer = "Victuailles en stock", OrderDate = DateTime.Parse("08-Jul-1997"), ShipVia = "Speedy Express" } + ); + + PrintMessage(message1, "Publisher 2", null); + + // "Any" means that only one subscriber will receive this message + // Another option is "All" where all subscribers recieve the message + topic.Publish(message1, DeliveryOption.Any); + + // wait for 1sec before publishing again + Thread.Sleep(1000); + PrintMessage(message2, "Publisher 2", null); + + topic.Publish(message2, DeliveryOption.Any); + }); + + // Now start both Async publisher tasks so each can publish 2 messages in parallel + publisher1Task.Start(); + publisher2Task.Start(); + + // Wait for 5sec + Thread.Sleep(5000); + + // Waiting for both publisher tasks to complete so we can end the sample + await Task.WhenAll(publisher1Task, publisher2Task); + + subscription1.UnSubscribe(); + subscription2.UnSubscribe(); + + Console.WriteLine("Sample completed successfully."); + } + + private static void MessageReceived_Subscription1(object sender, MessageEventArgs args) + { + PrintMessage(args.Message, null, "Subscriber 1"); + } + + private static void MessageReceived_Subscription2(object sender, MessageEventArgs args) + { + PrintMessage(args.Message, null, "Subscriber 2"); + } + + static void PrintMessage(IMessage message, string sender, string receiver) + { + var order = message.Payload as Order; + + lock (consoleLock) + { + if (!string.IsNullOrEmpty(sender)) Console.WriteLine($"{sender} publishes a message for Topic {topicName} ..."); + else if (!string.IsNullOrEmpty(receiver)) Console.WriteLine($"{receiver} receives message ..."); + + Console.WriteLine("OrderID, Customer, Order Date, Ship Via"); + Console.WriteLine($"- {order.OrderID}, {order.Customer}, {order.OrderDate.ToString("dd-MMM-yyyy")}, {order.ShipVia} \n"); + } + } + } + + [Serializable] + public class Order + { + public int OrderID { get; set; } + public string Customer { get; set; } + public DateTime OrderDate { get; set; } + public string ShipVia { get; set; } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/PubSubMessaging/Code/Properties/launchSettings.json b/playground/dotnetcore/PubSubMessaging/Code/Properties/launchSettings.json new file mode 100644 index 0000000..eac1bd6 --- /dev/null +++ b/playground/dotnetcore/PubSubMessaging/Code/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "PubSubMessaging": { + "commandName": "Project", + "commandLineArgs": "demoCache" + } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/PubSubMessaging/Code/PubSubMessaging.csproj b/playground/dotnetcore/PubSubMessaging/Code/PubSubMessaging.csproj new file mode 100644 index 0000000..3c2c35f --- /dev/null +++ b/playground/dotnetcore/PubSubMessaging/Code/PubSubMessaging.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + bin\ + false + false + Exe + + + + + + + diff --git a/playground/dotnetcore/SqlQueryCacheLookup/Code/Program.cs b/playground/dotnetcore/SqlQueryCacheLookup/Code/Program.cs new file mode 100644 index 0000000..4e263da --- /dev/null +++ b/playground/dotnetcore/SqlQueryCacheLookup/Code/Program.cs @@ -0,0 +1,180 @@ +using System.Collections; +using Alachisoft.NCache.Client; +using Alachisoft.NCache.Runtime.Caching; + +namespace NCache.Playground.Samples.SqlQueryCacheLookup +{ + // Use SQL to query for cached data in NCache based on object attributes and Tags instead of just keys. + // NCache SQL query requires indexes to be created on all objects being searched. One way is + // thru cache configuration. Second is through code using "Custom Attributes" to annotate object fields + // and create index on them automatically when they're added to the cache. + // In this sample, we're using "Custom Attributes" to create index on Product object. + + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Sample showing SQL queries to find data in NCache based on object attributes instead of keys.\n"); + + string cacheName = args[0]; + + Console.WriteLine($"Connecting to cache: {cacheName}"); + // Connect to the cache and return a cache handle + var cache = CacheManager.GetCache(cacheName); + Console.WriteLine($"Cache connected successfully: {cacheName}\n"); + + // Adds all the products to the cache. This automatically creates indexes on various + // attributes of Product object by using "Custom Attributes". + AddSampleData(cache); + + Console.WriteLine("Find products with Category IN (\"Electronics\", \"Stationery\") AND Price < $2000"); + + // $VALUE$ keyword means the entire object instead of individual attributes that are also possible + string sql = $"SELECT $VALUE$ FROM NCache.Playground.Samples.SqlQueryCacheLookup.Product WHERE Category IN (?, ?) AND Price < ?"; + + var sqlCommand = new QueryCommand(sql); + + ArrayList catParamList = new ArrayList(); + catParamList.Add("Electronics"); + catParamList.Add("Stationery"); + + sqlCommand.Parameters.Add("Category", catParamList); + sqlCommand.Parameters.Add("Price", new Decimal(2000)); + + // ExecuteReader returns ICacheReader with the query resultset + using (var reader = cache.SearchService.ExecuteReader(sqlCommand)) + { + var fetchedProducts = new List(); + if (reader.FieldCount > 0) + { + while (reader.Read()) + { + // GetValue() with $VALUE$ keyword returns the entire object instead of just one column + var result = reader.GetValue("$VALUE$"); + + fetchedProducts.Add(result); + } + } + PrintProducts(fetchedProducts); + } + + Console.WriteLine("Find all \"phone\" products (using LIKE operator) AND (Tag = \"Technology\" OR Tag = \"Gadgets\")"); + sql = $"SELECT $VALUE$ FROM NCache.Playground.Samples.SqlQueryCacheLookup.Product WHERE Name LIKE ? AND ($Tag$ = ? OR $Tag$ = ?)"; + + sqlCommand = new QueryCommand(sql); + + ArrayList tagList = new ArrayList(); + tagList.Add("Technology"); + tagList.Add("Gadgets"); + + sqlCommand.Parameters.Add("Name", "*Phone*"); + sqlCommand.Parameters.Add("$Tag$", tagList); + + using (var reader = cache.SearchService.ExecuteReader(sqlCommand)) + { + var fetchedProducts = new List(); + if (reader.FieldCount > 0) + { + while (reader.Read()) + { + var result = reader.GetValue("$VALUE$"); + fetchedProducts.Add(result); + } + } + PrintProducts(fetchedProducts); + } + + Console.WriteLine("GROUP BY query: Get a count of product by category with Price < $3000"); + sql = $"SELECT Category, COUNT(*) FROM NCache.Playground.Samples.SqlQueryCacheLookup.Product WHERE Price < ? GROUP BY Category"; + + sqlCommand = new QueryCommand(sql); + + sqlCommand.Parameters.Add("Price", new Decimal(3000)); + + using (var reader = cache.SearchService.ExecuteReader(sqlCommand)) + { + Console.WriteLine("Category, Count"); + if (reader.FieldCount > 0) + { + while (reader.Read()) + { + var category = reader.GetValue("Category"); + var count = reader.GetValue("COUNT()"); + Console.WriteLine($"- {category}, {count}"); + } + } + } + + Console.WriteLine("\nDelete Items by Tags \"Technology\" and \"Reading\""); + ArrayList removeTagsList = new ArrayList(); + removeTagsList.Add("Technology"); + removeTagsList.Add("Reading"); + + sql = "DELETE FROM NCache.Playground.Samples.SqlQueryCacheLookup.Product WHERE $Tag$ IN (?, ?)"; + sqlCommand = new QueryCommand(sql); + sqlCommand.Parameters.Add("$Tag$", removeTagsList); + var itemAffected = cache.SearchService.ExecuteNonQuery(sqlCommand); + Console.WriteLine($"{itemAffected} items removed from the cache.\n"); + + Console.WriteLine("Sample completed successfully."); + } + + static void AddSampleData(ICache cache) + { + Console.WriteLine("Adding products to the cache with tags..."); + + var laptop = new Product { ProductID = 13001, Name = "Laptop", Price = 2000, Category = "Electronics" }; + var kindle = new Product { ProductID = 13002, Name = "Kindle", Price = 1000, Category = "Electronics" }; + var book = new Product { ProductID = 13003, Name = "Book", Price = 100, Category = "Stationery" }; + var smartPhone = new Product { ProductID = 13004, Name = "Smart Phone", Price = 1000, Category = "Electronics" }; + var mobilePhone = new Product { ProductID = 13005, Name = "Mobile Phone", Price = 200, Category = "Electronics" }; + + var laptopCacheItem = new CacheItem(laptop) { Tags = new[] { new Tag("Technology"), new Tag("Gadgets") } }; + var kindleCacheItem = new CacheItem(kindle) { Tags = new[] { new Tag("Technology"), new Tag("Reading") } }; + var bookCacheItem = new CacheItem(book) { Tags = new[] { new Tag("Education"), new Tag("Reading") } }; + var smartPhoneCacheItem = new CacheItem(smartPhone) { Tags = new[] { new Tag("Technology"), new Tag("Communication") } }; + var mobilePhoneCacheItem = new CacheItem(mobilePhone) { Tags = new[] { new Tag("Technology"), new Tag("Communication") } }; + + var products = new Dictionary + { + { "13001", laptopCacheItem }, + { "13002", kindleCacheItem }, + { "13003", bookCacheItem }, + { "13004", smartPhoneCacheItem }, + { "13005", mobilePhoneCacheItem } + }; + + // Adds all the products to the cache. This automatically creates indexes on various + // attributes of Product object by using "Custom Attributes". + foreach (var product in products) + { + cache.Insert(product.Key, product.Value); + } + + var productValues = products.Values.Select(cacheItem => cacheItem.GetValue()); + PrintProducts(productValues); + } + + static void PrintProducts(IEnumerable products) + { + Console.WriteLine("ProductID, Name, Price, Category"); + foreach (var product in products) + { + Console.WriteLine($"- {product.ProductID}, {product.Name}, ${product.Price}, {product.Category}"); + } + Console.WriteLine(); + } + } + + [Serializable] + public class Product + { + public int ProductID { get; set; } + [QueryIndexed] + public string Name { get; set; } + [QueryIndexed] + public decimal Price { get; set; } + [QueryIndexed] + public string Category { get; set; } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/SqlQueryCacheLookup/Code/Properties/launchSettings.json b/playground/dotnetcore/SqlQueryCacheLookup/Code/Properties/launchSettings.json new file mode 100644 index 0000000..03bfdb2 --- /dev/null +++ b/playground/dotnetcore/SqlQueryCacheLookup/Code/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "SqlQueryCacheLookup": { + "commandName": "Project", + "commandLineArgs": "demoCache" + } + } +} \ No newline at end of file diff --git a/playground/dotnetcore/SqlQueryCacheLookup/Code/SqlQueryCacheLookup.csproj b/playground/dotnetcore/SqlQueryCacheLookup/Code/SqlQueryCacheLookup.csproj new file mode 100644 index 0000000..e5d4b1d --- /dev/null +++ b/playground/dotnetcore/SqlQueryCacheLookup/Code/SqlQueryCacheLookup.csproj @@ -0,0 +1,30 @@ + + + + Exe + net6.0 + enable + enable + bin\ + false + false + Exe + + + + + + + + + Always + + + Always + + + Always + + + + diff --git a/playground/java/BasicCacheOperations/Code/pom.xml b/playground/java/BasicCacheOperations/Code/pom.xml new file mode 100644 index 0000000..f53983f --- /dev/null +++ b/playground/java/BasicCacheOperations/Code/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + + + com.alachisoft.ncache.samples + BasicCacheOperations + 5.3.0 + + + 1.8 + 1.8 + + + + + com.alachisoft.ncache + ncache-client + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/../../../libs + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + bin/ + + + true + ../../../libs/ + ${project.groupId}.${project.artifactId} + + + + + + + + \ No newline at end of file diff --git a/playground/java/BasicCacheOperations/Code/src/main/java/com/alachisoft/ncache/samples/BasicCacheOperations.java b/playground/java/BasicCacheOperations/Code/src/main/java/com/alachisoft/ncache/samples/BasicCacheOperations.java new file mode 100644 index 0000000..174f60f --- /dev/null +++ b/playground/java/BasicCacheOperations/Code/src/main/java/com/alachisoft/ncache/samples/BasicCacheOperations.java @@ -0,0 +1,89 @@ +package com.alachisoft.ncache.samples; + +import java.io.Serializable; +import com.alachisoft.ncache.client.*; +import com.alachisoft.ncache.runtime.caching.expiration.*; +import com.alachisoft.ncache.runtime.util.TimeSpan; + +// Basic caching operations (CRUD) as an intro to NCache API + +public class BasicCacheOperations { + + public static void main(String[] args) throws Exception { + + System.out.println("Sample showing basic caching operations (CRUD) in NCache, along with expiration.\n"); + + String cacheName = args[0]; + System.out.println("Connecting to cache: " + cacheName); + + CacheConnectionOptions connectionOptions = new CacheConnectionOptions(); + connectionOptions.setIsolationLevel(IsolationLevel.OutProc); + + // Connect to the cache and return a cache handle + Cache cache = CacheManager.getCache(cacheName, connectionOptions); + System.out.println("Connected to Cache successfully: " + cacheName + "\n"); + + // Add product 10001 to the cache with a 5-minutes expiration + Product prod1 = new Product(10001, "Laptop", 1000, "Electronics"); + + String prod1Key = String.valueOf(prod1.getProductID()); + CacheItem productCacheItem = new CacheItem(prod1); + productCacheItem.setExpiration(new Expiration(ExpirationType.Absolute, TimeSpan.FromMinutes(5))); + + // Add to the cache with 5min absolute expiration (TTL). Item expires automatically + cache.add(prod1Key, productCacheItem); + + System.out.println("Product 10001 added successfully (5min expiration):"); + printProductDetails(prod1); + + // Get from the cache. If not found, a null is returned + Product retrievedprod1 = cache.get(prod1Key, Product.class); + if (retrievedprod1 != null) { + System.out.println("Product 10001 retrieved successfully:"); + printProductDetails(retrievedprod1); + } + + retrievedprod1.setPrice(3000); + + // Update product in the cache. If not found, it is added + CacheItem updatedProductCacheItem = new CacheItem(retrievedprod1); + updatedProductCacheItem.setExpiration(new Expiration(ExpirationType.Absolute, TimeSpan.FromMinutes(5))); + cache.insert(prod1Key, updatedProductCacheItem); + + System.out.println("Price for Product 10001 updated successfully:"); + printProductDetails(retrievedprod1); + + // Remove the item from the cache + cache.delete(prod1Key); + System.out.println("Deleted the product " + prod1Key + " from the cache...\n"); + + System.out.println("Sample completed successfully."); + cache.close(); + } + + private static void printProductDetails(Product product) { + System.out.println("ProductID, Name, Price, Category"); + System.out.println("- " + product.getProductID() + ", " + product.getName() + ", " + product.getPrice() + ", " + product.getCategory() + "\n"); + } +} + +// Sample class for Product +class Product implements Serializable { + private int productID; + private String name; + private int price; + private String category; + + public Product(int productID, String name, int price, String category) { + this.productID = productID; + this.name = name; + this.price = price; + this.category = category; + } + + public int getProductID() { return productID; } + public String getName() { return name; } + public double getPrice() { return price; } + public void setPrice(int price) { this.price = price; } + public String getCategory() { return category; } +} \ No newline at end of file diff --git a/playground/java/CacheItemLocking/Code/pom.xml b/playground/java/CacheItemLocking/Code/pom.xml new file mode 100644 index 0000000..9e864ab --- /dev/null +++ b/playground/java/CacheItemLocking/Code/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + + + com.alachisoft.ncache.samples + CacheItemLocking + 5.3.0 + + + + 1.8 + 1.8 + + + + + com.alachisoft.ncache + ncache-client + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/../../../libs + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + bin/ + + + true + ../../../libs/ + ${project.groupId}.${project.artifactId} + + + + + + + + \ No newline at end of file diff --git a/playground/java/CacheItemLocking/Code/src/main/java/com/alachisoft/ncache/samples/CacheItemLocking.java b/playground/java/CacheItemLocking/Code/src/main/java/com/alachisoft/ncache/samples/CacheItemLocking.java new file mode 100644 index 0000000..b672928 --- /dev/null +++ b/playground/java/CacheItemLocking/Code/src/main/java/com/alachisoft/ncache/samples/CacheItemLocking.java @@ -0,0 +1,88 @@ +package com.alachisoft.ncache.samples; + +import java.io.Serializable; +import com.alachisoft.ncache.client.Cache; +import com.alachisoft.ncache.client.CacheItem; +import com.alachisoft.ncache.client.CacheManager; +import com.alachisoft.ncache.client.LockHandle; +import com.alachisoft.ncache.runtime.caching.WriteThruOptions; +import com.alachisoft.ncache.runtime.util.TimeSpan; + +// Locking an item prevents other users from accessing it while you update it. +// You can lock with cache.GetCacheItem() or cache.Lock() and unlock with cache.Insert() or cache.Unlock() +// NOTE: Locking API is for application level locking. NCache already has its own internal locking +// for concurrency and thread-safe operations. + +public class CacheItemLocking { + + public static void main(String[] args) throws Exception { + + System.out.println("Sample showing item level lock and unlock in NCache.\n"); + String cacheName = args[0]; + + System.out.println("Connecting to cache: " + cacheName); + // Connect to the cache and return a cache handle + Cache cache = CacheManager.getCache(cacheName); + System.out.println("Connected to Cache successfully: " + cacheName + "\n"); + + Product prod1 = new Product(11001, "Laptop", 1000, "Electronics"); + + String prod1Key = String.valueOf(prod1.getProductID()); + System.out.println("Adding product 11001 to the cache..."); + + // Add a product to the cache. If it already exists, the operation will fail + cache.insert(prod1Key, prod1); + System.out.println("Product added successfully:"); + printProductDetails(prod1); + + // Get product 11001 and lock it in the cache + System.out.println("Get and lock product 11001 in the cache..."); + LockHandle lockHandle = new LockHandle(); + + // Lock the item and set a lock timeout of 10 seconds + CacheItem lockedCacheItem = cache.getCacheItem(prod1Key, true, TimeSpan.FromSeconds(10), lockHandle); + if (lockedCacheItem != null) { + System.out.println("Product 11001 retrieved and locked successfully:"); + Product retrievedProduct = (Product) lockedCacheItem.getValue(Product.class); + printProductDetails(retrievedProduct); + + // Change the price of product 11001 + retrievedProduct.setPrice(2000); + + // Update the item and release the lock + cache.insert(prod1Key, lockedCacheItem, new WriteThruOptions(), lockHandle, true); + System.out.println("Updated price of product 11001 and released the lock simultaneously in the cache..."); + + printProductDetails(retrievedProduct); + } + System.out.println("Sample completed successfully."); + cache.close(); + } + + private static void printProductDetails(Product product) { + System.out.println("ProductID, Name, Price, Category"); + System.out.println("- " + product.getProductID() + ", " + product.getName() + ", " + product.getPrice() + ", " + product.getCategory() + "\n"); + } +} + +// Sample class for Product +class Product implements Serializable { + private int productID; + private String name; + private int price; + private String category; + + public Product(int productID, String name, int price, String category) { + this.productID = productID; + this.name = name; + this.price = price; + this.category = category; + } + + public int getProductID() { return productID; } + public String getName() { return name; } + public double getPrice() { return price;} + public void setPrice(int price) { this.price = price;} + public String getCategory() { return category;} + +} diff --git a/playground/java/DataStructures/Code/pom.xml b/playground/java/DataStructures/Code/pom.xml new file mode 100644 index 0000000..8d63339 --- /dev/null +++ b/playground/java/DataStructures/Code/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + + + com.alachisoft.ncache.samples + DataStructures + 5.3.0 + + + + 1.8 + 1.8 + + + + + com.alachisoft.ncache + ncache-client + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/../../../libs + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + bin/ + + + true + ../../../libs/ + ${project.groupId}.${project.artifactId} + + + + + + + + \ No newline at end of file diff --git a/playground/java/DataStructures/Code/src/main/java/com/alachisoft/ncache/samples/DataStructures.java b/playground/java/DataStructures/Code/src/main/java/com/alachisoft/ncache/samples/DataStructures.java new file mode 100644 index 0000000..e70d35f --- /dev/null +++ b/playground/java/DataStructures/Code/src/main/java/com/alachisoft/ncache/samples/DataStructures.java @@ -0,0 +1,155 @@ +package com.alachisoft.ncache.samples; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Date; +import com.alachisoft.ncache.client.*; +import com.alachisoft.ncache.client.datastructures.DistributedList; +import com.alachisoft.ncache.client.datastructures.DistributedQueue; + +// Use NCache distributed data structures (List and Queue in this sample). NCache provides +// Set, Dictionary, and Counter data structures as well. These data structures are distributed in the cluster +// for scalability and accessible to all clients. + +public class DataStructures { + + public static void main(String[] args) throws Exception { + + System.out.println("Sample showing distributed data structures in NCache (List, Queue) for more powerful data management.\n"); + + String cacheName = args[0]; + + System.out.println("Connecting to cache: " + cacheName); + // Connect to the cache and return a cache handle + Cache cache = CacheManager.getCache(cacheName); + System.out.println("Connected to Cache successfully: " + cacheName + "\n"); + System.out.println("Create a List data structure and add products 'Electronics' to it..."); + + // Get the list if it already exists in the cache + DistributedList productList = cache.getDataStructuresManager().getList("productList", Product.class); + + if (productList == null) { + // Create a List data structure in the cache and then add products to it + productList = cache.getDataStructuresManager().createList("productList", Product.class); + } + + // These products are directly added to the cache inside the List data structure when you add them below + productList.add(new Product(15001, "Laptop", BigDecimal.valueOf(2000), "Electronics")); + productList.add(new Product(15002, "Kindle", BigDecimal.valueOf(1000), "Electronics")); + productList.add(new Product(15004, "Smart Phone", BigDecimal.valueOf(1000), "Electronics")); + productList.add(new Product(15005, "Mobile Phone", BigDecimal.valueOf(200), "Electronics")); + + printProductList(productList); + + System.out.println("Create a Queue data structure and add orders to it..."); + + // Get the queue if it already exists in the cache + DistributedQueue orderQueue = cache.getDataStructuresManager().getQueue("orderQueue", Order.class); + + if (orderQueue == null) { + // Create a Queue data structure and then add orders to it by maintaining their sequence + orderQueue = cache.getDataStructuresManager().createQueue("orderQueue", Order.class); + } + + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + // These orders are directly added to the cache inside the Queue data structure when you enqueue them below + orderQueue.add(new Order(16248, "Vins et alcools Chevalier", dateFormat.parse("1997-07-04"), "Federal Shipping")); + orderQueue.add(new Order(16249, "Toms Spezialitäten", dateFormat.parse("1997-07-05"), "Speedy Express")); + orderQueue.add(new Order(16250, "Hanari Carnes", dateFormat.parse("1997-07-07"), "United Package")); + orderQueue.add(new Order(16251, "Victuailles en stock", dateFormat.parse("1997-07-08"), "Speedy Express")); + + printOrderQueue(orderQueue); + + System.out.println("Fetch the list and print all items from the List data structure..."); + + // Fetch the List data structure from the cache and then access all items in it + DistributedList fetchedProductList = cache.getDataStructuresManager().getList("productList", Product.class); + + printProductList(fetchedProductList); + + System.out.println("Process all orders from the Queue one by one in a sequence\n"); + + // Fetch the Queue data structure from the cache and then process all orders one by one in a sequence + DistributedQueue fetchedOrderQueue = cache.getDataStructuresManager().getQueue("orderQueue", Order.class); + while (fetchedOrderQueue.size() > 0) { + Order order = orderQueue.poll(); + System.out.println("Process order : " + order.getOrderID()); + printOrder(order); + } + + // Removing all items from the list + productList.removeRange(0, productList.size()); + + System.out.println("Removed products from the List data structure.\n"); + + System.out.println("Sample completed successfully."); + cache.close(); + } + + static void printProductList(DistributedList productList) { + System.out.println("ProductID, Name, Price, Category, Tags"); + for (Product product : productList) { + System.out.println("- " + product.getProductID() + ", " + product.getName() + ", $" + product.getPrice() + ", " + product.getCategory()); + } + System.out.println(); + } + + static void printOrderQueue(DistributedQueue orderQueue) { + System.out.println("OrderID, Customer, Order Date, Ship Via"); + + for (Order order : orderQueue) { + System.out.println("- " + order.getOrderID() + ", " + order.getCustomer() + ", " + order.getOrderDate().toString() + ", " + order.getShipVia()); + } + System.out.println(); + } + + static void printOrder(Order order) { + System.out.println("OrderID, Customer, Order Date, Ship Via"); + System.out.println("- " + order.getOrderID() + ", " + order.getCustomer() + ", " + order.getOrderDate().toString() + ", " + order.getShipVia() + "\n"); + } +} + +// Sample class for Product +class Product implements Serializable { + private int productID; + private String name; + private BigDecimal price; + private String category; + + public Product(){ } + + public Product(int productID, String name, BigDecimal price, String category) { + this.productID = productID; + this.name = name; + this.price = price; + this.category = category; + } + + public int getProductID() { return productID; } + public String getName() { return name; } + public BigDecimal getPrice() { return price; } + public String getCategory() { return category; } +} + +// Sample class for Order +class Order implements Serializable { + private int orderID; + private String customer; + private Date orderDate; + private String shipVia; + + public Order(){ } + + public Order(int orderID, String customer, Date orderDate, String shipVia) { + this.orderID = orderID; + this.customer = customer; + this.orderDate = orderDate; + this.shipVia = shipVia; + } + + public int getOrderID() { return orderID; } + public String getCustomer() { return customer; } + public String getOrderDate() { return new SimpleDateFormat("yyyy-MM-dd").format(orderDate); } + public String getShipVia() { return shipVia; } +} diff --git a/playground/java/GroupingCachedData/Code/pom.xml b/playground/java/GroupingCachedData/Code/pom.xml new file mode 100644 index 0000000..09b730a --- /dev/null +++ b/playground/java/GroupingCachedData/Code/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + + + com.alachisoft.ncache.samples + GroupingCachedData + 5.3.0 + + + + 1.8 + 1.8 + + + + + com.alachisoft.ncache + ncache-client + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/../../../libs + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + bin/ + + + true + ../../../libs/ + ${project.groupId}.${project.artifactId} + + + + + + + + \ No newline at end of file diff --git a/playground/java/GroupingCachedData/Code/src/main/java/com/alachisoft/ncache/samples/GroupingCachedData.java b/playground/java/GroupingCachedData/Code/src/main/java/com/alachisoft/ncache/samples/GroupingCachedData.java new file mode 100644 index 0000000..fea7c71 --- /dev/null +++ b/playground/java/GroupingCachedData/Code/src/main/java/com/alachisoft/ncache/samples/GroupingCachedData.java @@ -0,0 +1,115 @@ +package com.alachisoft.ncache.samples; + +import java.io.Serializable; +import java.util.*; +import com.alachisoft.ncache.client.Cache; +import com.alachisoft.ncache.client.CacheItem; +import com.alachisoft.ncache.client.CacheManager; +import com.alachisoft.ncache.client.TagSearchOptions; +import com.alachisoft.ncache.runtime.caching.Tag; + +// Use the Tags feature of NCache to group items. First, use Tags while adding to the cache. Later, fetch by Tags + +public class GroupingCachedData { + + public static void main(String[] args) throws Exception { + + System.out.println("Sample showing the Tags feature of NCache to logically group related data to easily fetch later.\n"); + + // Connect to the cache + String cacheName = args[0]; + + System.out.println("Connecting to cache: " + cacheName); + // Connect to the cache and return a cache handle + Cache cache = CacheManager.getCache(cacheName); + System.out.println("Connected to Cache successfully: " + cacheName + "\n"); + + Product laptop = new Product(12001, "Laptop", 2000, "Electronics"); + Product kindle = new Product(12002, "Kindle", 1000, "Electronics"); + Product book = new Product(12003, "Book", 100, "Stationery"); + Product smartPhone = new Product(12004, "Smart Phone", 1000, "Electronics"); + Product mobilePhone = new Product(12005, "Mobile Phone", 200, "Electronics"); + + CacheItem laptopCacheItem = new CacheItem(laptop); + List laptopTags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Gadgets"))); + laptopCacheItem.setTags(laptopTags); + + CacheItem kindleCacheItem = new CacheItem(kindle); + List kindleTags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Reading"))); + kindleCacheItem.setTags(kindleTags); + + CacheItem bookCacheItem = new CacheItem(book); + List bookTags = new ArrayList<>(Arrays.asList(new Tag("Education"), new Tag("Reading"))); + bookCacheItem.setTags(bookTags); + + CacheItem smartPhoneCacheItem = new CacheItem(smartPhone); + List smartPhoneTags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Communication"))); + smartPhoneCacheItem.setTags(smartPhoneTags); + + CacheItem mobilePhoneCacheItem = new CacheItem(mobilePhone); + List mobilePhoneTags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Communication"))); + mobilePhoneCacheItem.setTags(mobilePhoneTags); + + Map products = new HashMap<>(); + products.put("12001", laptopCacheItem); + products.put("12002", kindleCacheItem); + products.put("12003", bookCacheItem); + products.put("12004", smartPhoneCacheItem); + products.put("12005", mobilePhoneCacheItem); + + // Add all the products to the cache. + for (Map.Entry product : products.entrySet()) { + cache.insert(product.getKey(), product.getValue()); + } + + Map technologyItems = cache.getSearchService().getByTag(new Tag("Technology")); + System.out.println("Got Items from the cache by Tag \"Technology\""); + printProductDetails(technologyItems.values()); + + // Get all items from the cache with this Tag. readingItems is a list of key-value pairs + Map readingItems = cache.getSearchService().getByTag(new Tag("Reading")); + System.out.println("Got the Items from the cache by Tag \"Reading\""); + printProductDetails(readingItems.values()); + + List tags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Reading"))); + + // Remove all items from the cache with any of the tags + cache.getSearchService().removeByTags(tags, TagSearchOptions.ByAnyTag); + System.out.println("Removed Items by Tags \"Technology\" and \"Reading\"\n"); + + System.out.println("Sample completed successfully."); + cache.close(); + } + + private static void printProductDetails(Collection items) { + if (items != null && !items.isEmpty()) { + System.out.println("ProductID, Name, Price, Category"); + for (Product product : items) { + System.out.println("- " + product.getProductID() + ", " + product.getName() + ", $" + product.getPrice() + ", " + product.getCategory()); + } + } else { + System.out.println("No items found..."); + } + System.out.println(); + } +} + +// Sample class for Product +class Product implements Serializable { + private int productID; + private String name; + private int price; + private String category; + + public Product(int productID, String name, int price, String category) { + this.productID = productID; + this.name = name; + this.price = price; + this.category = category; + } + + public int getProductID() { return productID; } + public String getName() { return name; } + public int getPrice() { return price; } + public String getCategory() { return category; } +} diff --git a/playground/java/HibernateCaching/Code/pom.xml b/playground/java/HibernateCaching/Code/pom.xml new file mode 100644 index 0000000..6f67ae1 --- /dev/null +++ b/playground/java/HibernateCaching/Code/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + + com.alachisoft.ncache.samples + HibernateCaching + 5.3.3 + + + 17 + 17 + UTF-8 + + + + com.alachisoft.ncache + ncache-hibernate + 5.3.3 + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.0 + + + org.apache.logging.log4j + log4j-core + 2.20.0 + + + org.apache.logging.log4j + log4j-api + 2.20.0 + + + org.hibernate.orm + hibernate-core + 6.3.1.Final + + + org.hibernate.validator + hibernate-validator + 8.0.1.Final + + + org.glassfish + jakarta.el + 4.0.2 + + + org.hibernate.orm + hibernate-jpamodelgen + 6.3.0.Final + provided + + + com.h2database + h2 + 2.1.214 + runtime + + + com.alachisoft.ncache + ncache-client + 5.3.2 + + + org.antlr + antlr4-runtime + 4.10.1 + + + + + central + https://repo.maven.apache.org/maven2 + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/../../../libs + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + bin/ + + + true + ../../../libs/ + ${project.groupId}.${project.artifactId} + + + + + + + \ No newline at end of file diff --git a/playground/java/HibernateCaching/Code/src/main/java/com/alachisoft/ncache/samples/HibernateCaching.java b/playground/java/HibernateCaching/Code/src/main/java/com/alachisoft/ncache/samples/HibernateCaching.java new file mode 100644 index 0000000..fdb442b --- /dev/null +++ b/playground/java/HibernateCaching/Code/src/main/java/com/alachisoft/ncache/samples/HibernateCaching.java @@ -0,0 +1,153 @@ +package com.alachisoft.ncache.samples; + + +import jakarta.persistence.Column; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.service.ServiceRegistry; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +// Use NCache integration with Hibernate to seamlessly cache query results in an L2 cache. +// Next time, Hibernate fetches these objects from the cache and saves an expensive database trip. +// We're using an H2 in-memory database that goes away when the process ends. + +public class HibernateCaching { + + public static void main(String[] args) { + + System.out.println("Sample showing Hibernate caching with NCache to save expensive database trips.\n"); + Logger.getLogger("org.hibernate").setLevel(Level.OFF); + + // Configure Hibernate properties programmatically + Properties hibernateProperties = new Properties(); + hibernateProperties.put("hibernate.connection.driver_class", "org.h2.Driver"); + hibernateProperties.put("hibernate.connection.url", "jdbc:h2:mem:testdb"); + hibernateProperties.put("hibernate.show_sql", "false"); + hibernateProperties.put("hibernate.hbm2ddl.auto", "create-drop"); + hibernateProperties.put("hibernate.cache.use_query_cache", "true"); + hibernateProperties.put("hibernate.cache.use_second_level_cache", "true"); + hibernateProperties.put("hibernate.cache.region.factory_class", "com.alachisoft.ncache.NCacheRegionFactory"); + hibernateProperties.put("cache-name", args[0]); + hibernateProperties.put("ncache.application_id", "myapp"); + + // Set other Hibernate properties as needed + Configuration configuration = new Configuration() + .setProperties(hibernateProperties).addAnnotatedClass(Product.class); + + // Build the ServiceRegistry + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()).build(); + + // Build the SessionFactory + SessionFactory factory = configuration.buildSessionFactory(serviceRegistry); + + // Create a List of Product objects + ArrayList products = (ArrayList) getProducts(); + + // Open a new Hibernate session to save products to the database. This also caches it + try (Session session = factory.openSession()) { + Transaction transaction = session.beginTransaction(); + // save() method saves products to the database and caches it too + System.out.println("ProductID, Name, Price, Category"); + for (Product product : products) { + System.out.println("- " + product.getProductID() + ", " + product.getName() + ", " + product.getPrice() + ", " + product.getCategory()); + session.save(product); + } + transaction.commit(); + System.out.println(); + } + + // Now open a new session to fetch products from the DB. + // But, these products are actually fetched from the cache + try (Session session = factory.openSession()) { + List productList = (List) session.createQuery("from Product").list(); + if (productList != null) { + System.out.println("Found and retrieved all product from the cache..."); + printProductDetails(productList); + } + } + System.out.println("Sample completed successfully."); + System.exit(0); + } + + // Helper method to print product details. + private static void printProductDetails(Collection items) { + System.out.println("ProductID, Name, Price, Category"); + if (items != null && !items.isEmpty()) { + for (Product product : items) { + System.out.println("- " + product.getProductID() + ", " + product.getName() + ", " + product.getPrice() + ", " + product.getCategory()); + } + } else { + System.out.println("No items found..."); + } + System.out.println(); + } + + // Helper method to create a list of Product objects. + private static List getProducts() + { + ArrayList products = new ArrayList<>(); + products.add(new Product(14001, "Laptop", 2000, "Electronics")); + products.add(new Product(14002, "Kindle", 1000, "Electronics")); + products.add(new Product(14003, "Book", 100, "Stationery")); + products.add(new Product(14004, "Smart Phone", 1000, "Electronics")); + products.add(new Product(14005, "Mobile Phone", 200, "Electronics")); + return products; + } +} + +// Sample class for Product +@jakarta.persistence.Entity +@jakarta.persistence.Cacheable +@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "CustomersCache") +class Product implements Serializable { + @jakarta.persistence.Id + private int productID; + @jakarta.persistence.Column + private String name; + @jakarta.persistence.Column + private double price; + @Column + private String category; + + public Product() { + } + + public Product(int productID, String name, double price, String category) { + this.productID = productID; + this.name = name; + this.price = price; + this.category = category; + } + + public int getProductID() { return productID; } + public String getName() { return name; } + public double getPrice() { return price; } + public String getCategory() { return category; } + +} + +// +// +// +// +// +// +// +// +// +// +// +// diff --git a/playground/java/HibernateCaching/NCacheHibernate.xml b/playground/java/HibernateCaching/NCacheHibernate.xml new file mode 100644 index 0000000..9ce7010 --- /dev/null +++ b/playground/java/HibernateCaching/NCacheHibernate.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/playground/java/PubSubMessaging/Code/pom.xml b/playground/java/PubSubMessaging/Code/pom.xml new file mode 100644 index 0000000..d65a46a --- /dev/null +++ b/playground/java/PubSubMessaging/Code/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + + + com.alachisoft.ncache.samples + PubSubMessaging + 5.3.0 + + + + 1.8 + 1.8 + + + + + com.alachisoft.ncache + ncache-client + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/../../../libs + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + bin/ + + + true + ../../../libs/ + ${project.groupId}.${project.artifactId} + + + + + + + + \ No newline at end of file diff --git a/playground/java/PubSubMessaging/Code/src/main/java/com/alachisoft/ncache/samples/PubSubMessaging.java b/playground/java/PubSubMessaging/Code/src/main/java/com/alachisoft/ncache/samples/PubSubMessaging.java new file mode 100644 index 0000000..1521a03 --- /dev/null +++ b/playground/java/PubSubMessaging/Code/src/main/java/com/alachisoft/ncache/samples/PubSubMessaging.java @@ -0,0 +1,164 @@ +package com.alachisoft.ncache.samples; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import com.alachisoft.ncache.client.*; +import com.alachisoft.ncache.client.services.MessagingService; +import com.alachisoft.ncache.runtime.caching.*; +import com.alachisoft.ncache.runtime.caching.messaging.MessageReceivedListener; + +// Use NCache Pub/Sub Messaging in this sample. In NCache, you can create multiple Topics +// and against each topic create multiple publishers and subscribers. In this sample, +// 2 parallel Async publisher tasks publish on the same topic and 2 subscribers receive +// messages from this topic. All messages use DeliveryOption. Any so only one subscriber +// gets each message. DeliveryOption.All is available but not used. + +public class PubSubMessaging { + static String topicName = "ORDERS"; + static final Object lock = new Object(); + + public static void main(String[] args) throws Exception { + + System.out.println("Sample showing NCache Pub/Sub Messaging for reliable real-time messaging between publishers and subscribers.\n"); + + String cacheName = args[0]; + + System.out.println("Connecting to cache: " + cacheName); + // Connect to the cache and return a cache handle + Cache cache = CacheManager.getCache(cacheName); + System.out.println("Connected to Cache successfully: " + cacheName + "\n"); + + System.out.println("Create a Topic " + topicName + " ...\n"); + + // Create a Topic in NCache. + MessagingService messagingService = cache.getMessagingService(); + Topic topic = messagingService.createTopic(topicName); + + System.out.println("Register 2 subscribers for Topic " + topicName + "\n"); + + // Register subscribers to this Topic + MessageReceivedListener subscriptionListener1 = new MessageReceivedListener() { + @Override + public void onMessageReceived(Object o, MessageEventArgs messageEventArgs) { + messageReceivedSubscription1(messageEventArgs.getMessage()); + } + }; + MessageReceivedListener subscriptionListener2 = new MessageReceivedListener() { + @Override + public void onMessageReceived(Object o, MessageEventArgs messageEventArgs) { + messageReceivedSubscription2(messageEventArgs.getMessage()); + } + }; + TopicSubscription subscription1 = topic.createSubscription(subscriptionListener1); + TopicSubscription subscription2 = topic.createSubscription(subscriptionListener2); + + // Create a thread pool for publishers + ExecutorService publisherThreadPool = Executors.newFixedThreadPool(2); + + // Create first asynchronous publisher task to publish 2 messages + publisherThreadPool.submit(() -> { + try { + Message message1 = new Message( + new Order(17348, "Vins et alcools Chevalier", LocalDate.parse("1997-07-04"), "Federal Shipping")); + + Message message2 = new Message( + new Order(17350, "Hanari Carnes", LocalDate.parse("1997-07-07"), "United Package")); + + printMessage(message1, "Publisher 1", null); + // "Any" means that only one subscriber will receive this message + // Another option is "All" where all subscribers receive the message + topic.publish(message1, DeliveryOption.Any); + + // Wait for 1 second before publishing again + Thread.sleep(1000); + printMessage(message2, "Publisher 1", null); + + topic.publish(message2, DeliveryOption.Any); + } catch (Exception ex) { + } + }); + + // Create second asynchronous publisher task to publish 2 messages + publisherThreadPool.submit(() -> { + try { + Message message1 = new Message( + new Order(17349, "Toms Spezialitäten", LocalDate.parse("1997-07-05"), "Speedy Express")); + + Message message2 = new Message( + new Order(17351, "Victuailles en stock", LocalDate.parse("1997-07-08"), "Speedy Express")); + + printMessage(message1, "Publisher 2", null); + + // "Any" means that only one subscriber will receive this message + // Another option is "All" where all subscribers receive the message + topic.publish(message1, DeliveryOption.Any); + + // Wait for 1 second before publishing again + Thread.sleep(1000); + printMessage(message2, "Publisher 2", null); + + topic.publish(message2, DeliveryOption.Any); + } catch (Exception ex) { + } + }); + + // Wait for 5 seconds + Thread.sleep(5000); + + // Unsubscribe subscribers + subscription1.unSubscribe(); + subscription2.unSubscribe(); + + // Shut down the thread pool + publisherThreadPool.shutdown(); + + topic.close(); + System.out.println("Sample completed successfully."); + cache.close(); + } + + private static void messageReceivedSubscription1(Message message) { + printMessage(message, null, "Subscriber 1"); + } + + private static void messageReceivedSubscription2(Message message) { + printMessage(message, null, "Subscriber 2"); + } + + static void printMessage(Message message, String sender, String receiver) { + Order order = (Order) message.getPayload(); + + synchronized (lock) { + if (sender != null && !sender.isEmpty()) { + System.out.println(sender + " publishes a message for Topic " + topicName + " ..."); + } else if (receiver != null && !receiver.isEmpty()) { + System.out.println(receiver + " receives message ..."); + } + + System.out.println("OrderID, Customer, Order Date, Ship Via"); + System.out.println("- " + order.getOrderID() + ", " + order.getCustomer() + ", " + + order.getOrderDate().toString() + ", " + order.getShipVia() + " \n"); + } + } +} +// Sample class for Order +class Order implements Serializable { + private int orderID; + private String customer; + private LocalDate orderDate; + private String shipVia; + + public Order(int orderID, String customer, LocalDate orderDate, String shipVia) { + this.orderID = orderID; + this.customer = customer; + this.orderDate = orderDate; + this.shipVia = shipVia; + } + + public int getOrderID() { return orderID; } + public String getCustomer() { return customer; } + public LocalDate getOrderDate() { return orderDate; } + public String getShipVia() { return shipVia; } +} \ No newline at end of file diff --git a/playground/java/SpringDataCaching/Code/pom.xml b/playground/java/SpringDataCaching/Code/pom.xml new file mode 100644 index 0000000..226cf2d --- /dev/null +++ b/playground/java/SpringDataCaching/Code/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + + com.alachisoft.ncache.samples + SpringDataCaching + 5.3.0 + + + 11 + 11 + + + + org.springframework + spring-context + 6.0.11 + + + org.springframework.boot + spring-boot-starter-data-jpa + 3.1.3 + + + com.alachisoft.ncache + ncache-spring + 5.3.0 + + + com.h2database + h2 + 2.2.222 + + + org.springframework.boot + spring-boot-starter-cache + 3.1.3 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + com.alachisoft.ncache.samples.SpringResultSetCaching + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/../../../libs + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + bin/ + + + true + ../../../libs/ + ${project.groupId}.${project.artifactId} + + + + + + + + diff --git a/playground/java/SpringDataCaching/Code/src/main/java/com/alachisoft/ncache/samples/SpringDataCaching.java b/playground/java/SpringDataCaching/Code/src/main/java/com/alachisoft/ncache/samples/SpringDataCaching.java new file mode 100644 index 0000000..5b4c648 --- /dev/null +++ b/playground/java/SpringDataCaching/Code/src/main/java/com/alachisoft/ncache/samples/SpringDataCaching.java @@ -0,0 +1,198 @@ +package com.alachisoft.ncache.samples; + +import com.alachisoft.ncache.spring.NCacheCacheManager; +import com.alachisoft.ncache.spring.configuration.SpringConfigurationManager; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.*; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.repository.CrudRepository; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.nio.file.Path; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +// Use NCache integration with Spring to seamlessly cache objects. Next time, Spring fetches these +// objects from the cache and saves an expensive database trip. We're using an H2 in-memory database +// that goes away when the process ends. + +@SpringBootApplication +@EnableCaching +public class SpringDataCaching { + public static void main(String[] args) { + + System.out.println("Sample showing Spring caching with NCache to save expensive database trips.\n"); + + // Running spring application + ConfigurableApplicationContext context = SpringApplication.run(SpringDataCaching.class, args); + + // Get a Spring Service to save objects in the DB. This also caches them with 5min absolute (TTL) expiration. + BookService service = context.getBean(BookService.class); + service.save(new Book(18001, "The Second Machine Age", "Erik Brynjolfsson, Andrew McAfee", new Date(2014, 0, 20))); + service.save(new Book(18002, "Harry Potter and the Prisoner of Azkaban", "J.K. Rowling", new Date(1999, 6, 8))); + service.save(new Book(18003, "Cloud Computing | Methodology, Systems, and Applications", "Lizhe Wang, Rajiv Ranjan", new Date(2011, 9, 3))); + service.save(new Book(18004, "The Alchemist", "Paulo Coelho", new Date(19993, 0, 1))); + + // Print all saved books details + printBooks(service.listAll()); + + System.out.println("\nFinding book by isbn# ..."); + + // Use Spring Service to get a book from the DB. It actually comes from the cache + Book foundBook = service.findBookByIsbn(18001); + printBookDetails(foundBook); + + // Use Spring Service to save "updated" book to the DB. It updates the cache too + System.out.println("\nUpdating the book author in DB..."); + foundBook.setAuthor("New Author"); + Book UpdatedBook = service.update(foundBook); + + System.out.println("\nUpdated book info..."); + printBookDetails(UpdatedBook); + + + System.out.println("\n" + "Sample completed successfully."); + context.close(); + System.exit(0); + } + + // Helper method to print book details. + private static void printBooks(List books) { + System.out.println("Total Books: " + books.size()); + + System.out.println("BookID, ISBN, Title, Author"); + for (Book book : books) { + System.out.println("- " + book.getId() + ", " + book.getISBN() + ", " + book.getTitle() + ", " + book.getAuthor()); + } + } + + // Helper method to print book details. + private static void printBookDetails(Book book) { + System.out.println("BookID, ISBN, Title, Author"); + System.out.println("- " + book.getId() + ", " + book.getISBN() + ", " + book.getTitle() + ", " + book.getAuthor()); + } +} + +// Class to get connected with cache. +@Configuration +class CachingConfiguration { + @Autowired + private ApplicationArguments applicationArguments; + @Bean + public CacheManager cacheManager() { + String[] args = applicationArguments.getSourceArgs(); + String resource = Path.of(System.getenv("NCHOME"), "config/ncache-spring.xml").toString(); + + SpringConfigurationManager springConfigurationManager = new SpringConfigurationManager(); + springConfigurationManager.setConfigFile(resource); + + Properties properties = new Properties(); + properties.setProperty("ncacheid-instance", args[0]); + + NCacheCacheManager cacheManager = new NCacheCacheManager(); + cacheManager.setSpringConfigurationManager(springConfigurationManager); + + return cacheManager; + } +} + +//Helper class to perform CRUD operations. +@Service +class BookService { + @Autowired + private BookRepository repo; + + public List listAll() { + return repo.findAll(); + } + + @CachePut(value = "books", key = "#book.getISBN()") + public Book save(Book book) { return repo.save(book); } + + @CachePut(value = "books", key = "#book.getISBN()") + public Book update(Book book) { return repo.save(book); } + + @Cacheable(value = "books", key = "#id") + public Book get(int id) { + return repo.findById(id); + } + + @Cacheable(value = "books", key = "#isbn") + public Book findBookByIsbn(long isbn) { + return repo.findBookByIsbn(isbn); + } + + @CacheEvict(value = "books", allEntries = true) + public void delete(int id) { + repo.deleteById(id); + } +} + +@Repository +interface BookRepository extends CrudRepository { + Book findById(int id); + @NonNull + List findAll(); + void deleteById(int id); + Book findBookByIsbn(long isbn); +} + +// Book class to store book details. +@Entity +class Book implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Integer id; + private long isbn; + private String title; + private String author; + private Date publishedDate; + + public Book() { + } + + public Book(long isbn, String title, + String author, Date publishedDate) { + this.isbn = isbn; + this.title = title; + this.author = author; + this.publishedDate = publishedDate; + } + + public void setAuthor(String author) { this.author = author; } + public long getISBN() { return isbn; } + public void setId(Integer id) { this.id = id; } + public void setISBN(long isbn) { this.isbn = isbn; } + public Integer getId() { return id; } + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + public String getAuthor() { return author; } + public Date getPublishedDate() { return publishedDate; } + public void setPublishedDate(Date publishedDate) { this.publishedDate = publishedDate; } +} + +//ncache-spring.xml: + +// +// +// +// +// \ No newline at end of file diff --git a/playground/java/SpringDataCaching/Code/src/main/resources/application.properties b/playground/java/SpringDataCaching/Code/src/main/resources/application.properties new file mode 100644 index 0000000..d8a6c94 --- /dev/null +++ b/playground/java/SpringDataCaching/Code/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.hibernate.ddl-auto=update +logging.level.root=OFF +#spring.main.banner-mode=off \ No newline at end of file diff --git a/playground/java/SpringDataCaching/Code/src/main/resources/beans.xml b/playground/java/SpringDataCaching/Code/src/main/resources/beans.xml new file mode 100644 index 0000000..c03a565 --- /dev/null +++ b/playground/java/SpringDataCaching/Code/src/main/resources/beans.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/playground/java/SpringDataCaching/Code/src/main/resources/ncache-spring.xml b/playground/java/SpringDataCaching/Code/src/main/resources/ncache-spring.xml new file mode 100644 index 0000000..954ffab --- /dev/null +++ b/playground/java/SpringDataCaching/Code/src/main/resources/ncache-spring.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/playground/java/SqlQueryCacheLookup/Code/pom.xml b/playground/java/SqlQueryCacheLookup/Code/pom.xml new file mode 100644 index 0000000..db6c11a --- /dev/null +++ b/playground/java/SqlQueryCacheLookup/Code/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + + + com.alachisoft.ncache.samples + SqlQueryCacheLookup + 5.3.0 + + + + 1.8 + 1.8 + + + + + com.alachisoft.ncache + ncache-client + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/../../../libs + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + bin/ + + + true + ../../../libs/ + ${project.groupId}.${project.artifactId} + + + + + + + + \ No newline at end of file diff --git a/playground/java/SqlQueryCacheLookup/Code/src/main/java/com/alachisoft/ncache/samples/SqlQueryCacheLookup.java b/playground/java/SqlQueryCacheLookup/Code/src/main/java/com/alachisoft/ncache/samples/SqlQueryCacheLookup.java new file mode 100644 index 0000000..c52e499 --- /dev/null +++ b/playground/java/SqlQueryCacheLookup/Code/src/main/java/com/alachisoft/ncache/samples/SqlQueryCacheLookup.java @@ -0,0 +1,192 @@ +package com.alachisoft.ncache.samples; + +import java.math.BigDecimal; +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + +import com.alachisoft.ncache.client.*; +import com.alachisoft.ncache.runtime.caching.Tag; +import com.alachisoft.ncache.runtime.exceptions.CacheException; +import com.alachisoft.ncache.runtime.exceptions.OperationFailedException; +import com.alachisoft.ncache.client.QueryIndexable; + +// Use SQL to query for cached data in NCache based on object attributes and Tags instead of just keys. +// NCache SQL query requires indexes to be created on all objects being searched. One way is +// thru cache configuration. Second is through code using "Custom Attributes" to annotate object fields +// and create index on them automatically when they're added to the cache. +// In this sample, we're using "Custom Attributes" to create index on Product object. + +public class SqlQueryCacheLookup { + + public static void main(String[] args) throws Exception { + + System.out.println("Sample showing SQL queries to find data in NCache based on object attributes instead of keys.\n"); + + String cacheName = args[0]; + + System.out.println("Connecting to cache: " + cacheName); + // Connect to the cache and return a cache handle + Cache cache = CacheManager.getCache(cacheName); + System.out.println("Connected to Cache successfully: " + cacheName + "\n"); + + // Adds all the products to the cache. This automatically creates indexes on various + // attributes of Product object by using "Custom Attributes". + addSampleData(cache); + + System.out.println("Find products with Category IN (\"Electronics\", \"Stationery\") AND Price < $2000"); + + // $VALUE$ keyword means the entire object instead of individual attributes that are also possible + String sql = "SELECT $VALUE$ FROM com.alachisoft.ncache.samples.Product WHERE category IN (?, ?) AND price < ?"; + + QueryCommand sqlCommand = new QueryCommand(sql); + + List catParamList = new ArrayList<>(Arrays.asList(("Electronics"), ("Stationery"))); + sqlCommand.getParameters().put("category", catParamList); + sqlCommand.getParameters().put("price", 2000); + + // ExecuteReader returns ICacheReader with the query resultset + CacheReader resultSet = cache.getSearchService().executeReader(sqlCommand); + List fetchedProducts = new ArrayList<>(); + if (resultSet.getFieldCount() > 0) { + while (resultSet.read()) { + // getValue() with $VALUE$ keyword returns the entire object instead of just one column + fetchedProducts.add(resultSet.getValue("$VALUE$", Product.class)); + } + } + printProducts(fetchedProducts); + + System.out.println("Find all \"phone\" products (using LIKE operator) AND (Tag = \"Technology\" OR Tag = \"Gadgets\")"); + sql = "SELECT $VALUE$ FROM com.alachisoft.ncache.samples.Product WHERE name LIKE ? AND ($Tag$ = ? OR $Tag$ = ?)"; + + List tagList = new ArrayList<>(Arrays.asList(("Technology"), ("Gadgets"))); + + sqlCommand = new QueryCommand(sql); + sqlCommand.getParameters().put("name", "*Phone*"); + sqlCommand.getParameters().put("$Tag$", tagList); + + resultSet = cache.getSearchService().executeReader(sqlCommand); + fetchedProducts.clear(); + if (resultSet.getFieldCount() > 0) { + while (resultSet.read()) { + // getValue() with $VALUE$ keyword returns the entire object instead of just one column + fetchedProducts.add(resultSet.getValue("$VALUE$", Product.class)); + } + } + printProducts(fetchedProducts); + + System.out.println("GROUP BY query: Get a count of product by category with Price < $3000"); + sql = "SELECT category, COUNT(*) FROM com.alachisoft.ncache.samples.Product WHERE price < ? GROUP BY category"; + + sqlCommand = new QueryCommand(sql); + + sqlCommand.getParameters().put("price", 3000); + + CacheReader groupByResultSet = cache.getSearchService().executeReader(sqlCommand); + System.out.println("Category, Count"); + if (groupByResultSet.getFieldCount() > 0) { + while (groupByResultSet.read()) { + String category = groupByResultSet.getValue(0, String.class); + BigDecimal count = groupByResultSet.getValue(1, BigDecimal.class); + System.out.println("- " + category + ", " + count); + } + } + + System.out.println("\nDelete Items by Tags \"Technology\" and \"Reading\""); + sql = "DELETE FROM com.alachisoft.ncache.samples.Product WHERE $Tag$ IN (?, ?)"; + sqlCommand = new QueryCommand(sql); + + List removeTagsList = new ArrayList<>(Arrays.asList(("Technology"), ("Reading"))); + sqlCommand.getParameters().put("$Tag$", removeTagsList); + + int itemsRemoved = cache.getSearchService().executeNonQuery(sqlCommand); + System.out.println(itemsRemoved + " items removed from the cache.\n"); + + System.out.println("Sample completed successfully."); + cache.close(); + } + + static void addSampleData(Cache cache) throws CacheException { + System.out.println("Adding products to the cache with tags..."); + + Product laptop = new Product(13001, "Laptop", 2000, "Electronics"); + Product kindle = new Product(13002, "Kindle", 1000, "Electronics"); + Product book = new Product(13003, "Book", 100, "Stationery"); + Product smartPhone = new Product(13004, "Smart Phone", 1000, "Electronics"); + Product mobilePhone = new Product(13005, "Mobile Phone", 200, "Electronics"); + + CacheItem laptopCacheItem = new CacheItem(laptop); + List laptopTags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Gadgets"))); + laptopCacheItem.setTags(laptopTags); + + CacheItem kindleCacheItem = new CacheItem(kindle); + List kindleTags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Reading"))); + kindleCacheItem.setTags(kindleTags); + + CacheItem bookCacheItem = new CacheItem(book); + List bookTags = new ArrayList<>(Arrays.asList(new Tag("Education"), new Tag("Reading"))); + bookCacheItem.setTags(bookTags); + + CacheItem smartPhoneCacheItem = new CacheItem(smartPhone); + List smartPhoneTags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Communication"))); + smartPhoneCacheItem.setTags(smartPhoneTags); + + CacheItem mobilePhoneCacheItem = new CacheItem(mobilePhone); + List mobilePhoneTags = new ArrayList<>(Arrays.asList(new Tag("Technology"), new Tag("Communication"))); + mobilePhoneCacheItem.setTags(mobilePhoneTags); + + Map products = new HashMap<>(); + products.put("13001", laptopCacheItem); + products.put("13002", kindleCacheItem); + products.put("13003", bookCacheItem); + products.put("13004", smartPhoneCacheItem); + products.put("13005", mobilePhoneCacheItem); + + // Adds all the products to the cache. This automatically creates indexes on various + // attributes of Product object by using "Custom Attributes". + for (Map.Entry product : products.entrySet()) { + cache.insert(product.getKey(), product.getValue()); + } + + List productValues = products.values().stream() + .map(cacheItem -> { + try { + return (Product) cacheItem.getValue(Product.class); + } catch (OperationFailedException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toList()); + printProducts(productValues); + } + + static void printProducts(List products) { + System.out.println("ProductID, Name, Price, Category"); + for (Product product : products) { + System.out.println("- " + product.getProductID() + ", " + product.getName() + ", $" + product.getPrice() + ", " + product.getCategory()); + } + System.out.println(); + } +} + +// Sample class for Product +@QueryIndexable +class Product implements Serializable { + private int productID; + private String name; + private int price; + private String category; + + public Product(int productID, String name, int price, String category) { + this.productID = productID; + this.name = name; + this.price = price; + this.category = category; + } + + public int getProductID() { return productID; } + public String getName() { return name; } + public double getPrice() { return price; } + public void setPrice(int price) { this.price = price; } + public String getCategory() { return category; } +} \ No newline at end of file