public virtual void TestParallelInsertsAndRemoves(TestCacheProvider cacheProvider) { var cacheService = EFServiceProvider.GetCacheServiceProvider(cacheProvider); var efCachePolicy = new EFCachePolicy().Timeout(TimeSpan.FromMinutes(10)).ExpirationMode(CacheExpirationMode.Absolute); var tests = new List <Action>(); for (var i = 0; i < 4000; i++) { var i1 = i; tests.Add(() => cacheService.InsertValue( new EFCacheKey(new HashSet <string> { "entity1", "entity2" }) { KeyHash = $"EF_key{i1}" }, new EFCachedData { NonQuery = i1 }, efCachePolicy)); } for (var i = 0; i < 400; i++) { if (i % 2 == 0) { tests.Add(() => cacheService.InvalidateCacheDependencies(new EFCacheKey(new HashSet <string> { "entity1" }) { KeyHash = $"EF_key{i}" })); } else { tests.Add(() => cacheService.InvalidateCacheDependencies(new EFCacheKey(new HashSet <string> { "entity2" }) { KeyHash = $"EF_key{i}" })); } } Parallel.Invoke(tests.OrderBy(a => RandomNumberProvider.Next()).ToArray()); var value1 = cacheService.GetValue(new EFCacheKey(new HashSet <string> { "entity1", "entity2" }) { KeyHash = "EF_key1" }, efCachePolicy); Assert.IsNull(value1); }
public void TestTransactionRollbackShouldNotInvalidateTheCacheDependencyAutomatically(TestCacheProvider cacheProvider) { EFServiceProvider.RunInContext(cacheProvider, LogLevel.Debug, false, (context, loggerProvider) => { var isActive = true; var name = "Product1"; var list1 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list1.Any()); var list2 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list2.Any()); try { var newProduct = new Product { IsActive = false, ProductName = "Product1", // It has an `IsUnique` constraint. ProductNumber = RandomNumberProvider.Next().ToString(), Notes = "Notes ...", UserId = 1 }; context.Products.Add(newProduct); context.SaveChanges(); // it uses a transaction behind the scene. } catch (Exception ex) { // NOTE: This doesn't work with `EntityFrameworkInMemoryDatabase`. Because it doesn't support constraints. // ProductName is duplicate here and should throw an exception on save changes // and rollback the transaction automatically. Console.WriteLine(ex.ToString()); } var list3 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list3.Any()); }); }
public void TestInsertingDataIntoTheSameTableShouldInvalidateTheCacheAutomatically(TestCacheProvider cacheProvider) { EFServiceProvider.RunInContext(cacheProvider, LogLevel.Debug, false, (context, loggerProvider) => { var isActive = true; var name = "Product2"; var list1 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list1.Any()); var list2 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list2.Any()); var newProduct = new Product { IsActive = false, ProductName = $"Product{RandomNumberProvider.Next()}", ProductNumber = RandomNumberProvider.Next().ToString(), Notes = "Notes ...", UserId = 1 }; context.Products.Add(newProduct); context.SaveChanges(); var list3 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list3.Any()); }); }
public void TestRemoveTptDataShouldInvalidateTheCacheAutomatically(TestCacheProvider cacheProvider) { EFServiceProvider.RunInContext(cacheProvider, LogLevel.Debug, false, (context, loggerProvider) => { var list1 = context.Posts.OfType <Page>().Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)).ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); var list2 = context.Posts.OfType <Page>().Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)).ToList(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); var post1 = context.Posts.First(post => post.Id == 1); post1.Title = $"Post{RandomNumberProvider.Next()}"; context.SaveChanges(); var list3 = context.Posts.OfType <Page>().Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)).ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); }); }
public void TestInsertingDataToRelatedTablesShouldInvalidateTheCacheDependencyAutomatically(TestCacheProvider cacheProvider) { EFServiceProvider.RunInContext(cacheProvider, LogLevel.Debug, false, (context, loggerProvider) => { var isActive = true; var name = "Product1"; var list1 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list1.Any()); var list2 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list2.Any()); var tag = new Tag { Name = $"Tag {RandomNumberProvider.Next()}" }; context.Tags.Add(tag); context.SaveChanges(); var list3 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list3.Any()); }); }
public void TestInsertingDataToOtherTablesShouldNotInvalidateTheCacheDependencyAutomatically(bool useRedis) { EFServiceProvider.RunInContext(useRedis, LogLevel.Information, false, (context, loggerProvider) => { var isActive = true; var name = "Product4"; var list1 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsTrue(!list1.Any()); var list2 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsTrue(!list2.Any()); var user = new User { Name = $"User {RandomNumberProvider.Next()}" }; context.Users.Add(user); context.SaveChanges(); var list3 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsTrue(!list3.Any()); }); }
public async Task TestCacheInvalidationWorksWithSPs(bool useRedis) { await EFServiceProvider.RunInContextAsync(useRedis, LogLevel.Information, false, async (context, loggerProvider) => { var blogId = 1; var blogs = await context.Set <BlogData>() .FromSqlRaw("usp_GetBlogData {0}", blogId) .Cacheable() .ToListAsync(); Assert.IsTrue(blogs.Any()); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); blogs = await context.Set <BlogData>() .FromSqlRaw("usp_GetBlogData {0}", blogId) .Cacheable() .ToListAsync(); Assert.IsTrue(blogs.Any()); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); var product = new Product { IsActive = false, ProductName = $"Product{RandomNumberProvider.Next()}", ProductNumber = RandomNumberProvider.Next().ToString(), Notes = "Notes ...", UserId = 1 }; context.Products.Add(product); await context.SaveChangesAsync(); blogs = await context.Set <BlogData>() .FromSqlRaw("usp_GetBlogData {0}", blogId) .Cacheable() .ToListAsync(); Assert.IsTrue(blogs.Any()); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); }); }
public void TestRemoveDataShouldInvalidateTheCacheAutomatically(TestCacheProvider cacheProvider) { EFServiceProvider.RunInContext(cacheProvider, LogLevel.Debug, false, (context, loggerProvider) => { var isActive = false; var name = "Product4"; var list1 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsNotNull(list1); var list2 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsTrue(list2.Any()); var product1 = context.Products.First(product => product.ProductName == name); product1.Notes = $"Test ... {RandomNumberProvider.Next()}"; context.SaveChanges(); var list3 = context.Products.Include(x => x.TagProducts).ThenInclude(x => x.Tag) .OrderBy(product => product.ProductNumber) .Where(product => product.IsActive == isActive && product.ProductName == name) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .ToList(); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsNotNull(list3); }); }
public void TestAddThenRemoveDataShouldInvalidateTheCacheAutomatically(TestCacheProvider cacheProvider) { EFServiceProvider.RunInContext(cacheProvider, LogLevel.Debug, false, (context, loggerProvider) => { User user1; const string user1Name = "User1"; if (!context.Users.Any(user => user.Name == user1Name)) { user1 = new User { Name = user1Name, AddDate = new DateTime(2020, 4, 3, 17, 50, 39, 503), UpdateDate = null, Points = 1000, IsActive = true, ByteValue = 1, CharValue = 'C', DateTimeOffsetValue = new DateTimeOffset(new DateTime(2020, 4, 3, 17, 50, 39, 503)), DecimalValue = 1.1M, DoubleValue = 1.3, FloatValue = 1.2f, GuidValue = new Guid("236bbe40-b861-433c-8789-b152a99cfe3e"), TimeSpanValue = new TimeSpan(1, 0, 0, 0, 0), ShortValue = 2, ByteArrayValue = new byte[] { 1, 2 }, UintValue = 1, UlongValue = 1, UshortValue = 1 }; user1 = context.Users.Add(user1).Entity; } else { user1 = context.Users.First(user => user.Name == user1Name); } var userOne = context.Users.Cacheable().First(user => user.Name == user1Name); userOne = context.Users.Cacheable().First(user => user.Name == user1Name); Assert.IsNotNull(userOne); loggerProvider.ClearItems(); var product = new Product { IsActive = false, ProductName = $"Product{RandomNumberProvider.Next()}", ProductNumber = RandomNumberProvider.Next().ToString(), Notes = "Notes ...", UserId = 1 }; context.Products.Add(product); context.SaveChanges(); var p98 = context.Products .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .FirstOrDefault(p => p.ProductId == product.ProductId); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsNotNull(p98); var firstQueryWithWhereClauseResult = context.Products.Where(p => p.ProductId == product.ProductId) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .FirstOrDefault(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsNotNull(firstQueryWithWhereClauseResult); context.Products.Remove(product); context.SaveChanges(); p98 = context.Products .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .FirstOrDefault(p => p.ProductId == product.ProductId); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsNull(p98); var firstQueryWithWhereClauseResult2 = context.Products.Where(p => p.ProductId == product.ProductId) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .FirstOrDefault(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsNull(firstQueryWithWhereClauseResult2); p98 = context.Products.FirstOrDefault(p => p.ProductId == product.ProductId); Assert.IsNull(p98); }); }
public void TestAddThenRemoveDataShouldInvalidateTheCacheAutomatically(bool useRedis) { EFServiceProvider.RunInContext(useRedis, LogLevel.Information, false, (context, loggerProvider) => { User user1; const string user1Name = "User1"; if (!context.Users.Any(user => user.Name == user1Name)) { user1 = new User { Name = user1Name }; user1 = context.Users.Add(user1).Entity; } else { user1 = context.Users.First(user => user.Name == user1Name); } var product = new Product { IsActive = false, ProductName = $"Product{RandomNumberProvider.Next()}", ProductNumber = RandomNumberProvider.Next().ToString(), Notes = "Notes ...", UserId = 1 }; context.Products.Add(product); context.SaveChanges(); var p98 = context.Products .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .FirstOrDefault(p => p.ProductId == product.ProductId); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsNotNull(p98); var firstQueryWithWhereClauseResult = context.Products.Where(p => p.ProductId == product.ProductId) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .FirstOrDefault(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsNotNull(firstQueryWithWhereClauseResult); context.Products.Remove(product); context.SaveChanges(); p98 = context.Products .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .FirstOrDefault(p => p.ProductId == product.ProductId); Assert.AreEqual(0, loggerProvider.GetCacheHitCount()); Assert.IsNull(p98); var firstQueryWithWhereClauseResult2 = context.Products.Where(p => p.ProductId == product.ProductId) .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) .FirstOrDefault(); Assert.AreEqual(1, loggerProvider.GetCacheHitCount()); Assert.IsNull(firstQueryWithWhereClauseResult2); p98 = context.Products.FirstOrDefault(p => p.ProductId == product.ProductId); Assert.IsNull(p98); }); }