context: using System;
  using System.Collections;
  using System.Threading;
  using NHibernate.Stat;
  using NUnit.Framework;
  using NHibernate.Transform;
  
  namespace NHibernate.Test.SecondLevelCacheTests
  {
  	[TestFixture]
  	public class ScalarQueryFixture : TestCase
  	{
  		protected override string MappingsAssembly
  		{
  			get { return "NHibernate.Test"; }
  		}
  
  		protected override IList Mappings
  		{
  			get { return new[] { "SecondLevelCacheTest.Item.hbm.xml" }; }
  		}
  
  		protected override void Configure(Cfg.Configuration configuration)
  		{
  			configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true");
  		}
  
  		public void FillDb(int startId)
  		{
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				for (int i = startId; i < startId + 10; i++)
  				{
  					s.Save(new AnotherItem { Id = i, Name = (i / 2).ToString() });
  				}
  				tx.Commit();
  			}
  		}
  
  		public void CleanUp()
  		{
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				s.Delete("from AnotherItem");
  				tx.Commit();
  			}
  		}
  
  		[Test]
  		public void ShouldHitCacheUsingNamedQueryWithProjection()
  		{
  			FillDb(1);
  			sessions.Statistics.Clear();
  
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				s.GetNamedQuery("Stat").List();
  				tx.Commit();
  			}
  
  			Assert.That(sessions.Statistics.QueryExecutionCount, Is.EqualTo(1));
  			Assert.That(sessions.Statistics.QueryCachePutCount, Is.EqualTo(1));
  			Assert.That(sessions.Statistics.QueryCacheHitCount, Is.EqualTo(0));
  
  			sessions.Statistics.Clear();
  
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				s.GetNamedQuery("Stat").List();
  				tx.Commit();
  			}
  
  			Assert.That(sessions.Statistics.QueryExecutionCount, Is.EqualTo(0));
  			Assert.That(sessions.Statistics.QueryCacheHitCount, Is.EqualTo(1));
  
  			sessions.Statistics.LogSummary();
  			CleanUp();
  		}
  
  		[Test]
  		public void ShouldHitCacheUsingQueryWithProjection()
  		{
  			FillDb(1);
  			sessions.Statistics.Clear();
  
  			int resultCount;
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				resultCount =
  					s.CreateQuery("select ai.Name, count(*) from AnotherItem ai group by ai.Name").SetCacheable(true).SetCacheRegion(
  						"Statistics").List().Count;
  				tx.Commit();
  			}
  
  			Assert.That(sessions.Statistics.QueryExecutionCount, Is.EqualTo(1));
  			Assert.That(sessions.Statistics.QueryCachePutCount, Is.EqualTo(1));
  			Assert.That(sessions.Statistics.QueryCacheHitCount, Is.EqualTo(0));
  
  			sessions.Statistics.Clear();
  
  			int secondResultCount;
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				secondResultCount = s.CreateQuery("select ai.Name, count(*) from AnotherItem ai group by ai.Name")
  					.SetCacheable(true).SetCacheRegion("Statistics").List().Count;
  				tx.Commit();
  			}
  
  			Assert.That(sessions.Statistics.QueryExecutionCount, Is.EqualTo(0));
  			Assert.That(sessions.Statistics.QueryCacheHitCount, Is.EqualTo(1));
  			Assert.That(secondResultCount, Is.EqualTo(resultCount));
  
  			sessions.Statistics.LogSummary();
  			CleanUp();
  		}
  
  		[Test]
  		public void QueryCacheInvalidation()
  		{
  			sessions.EvictQueries();
  			sessions.Statistics.Clear();
  
  			const string queryString = "from Item i where i.Name='widget'";
  
  			object savedId = CreateItem(queryString);
  
  			QueryStatistics qs = sessions.Statistics.GetQueryStatistics(queryString);
  			EntityStatistics es = sessions.Statistics.GetEntityStatistics(typeof(Item).FullName);
  
  			Thread.Sleep(200);
  
  			IList result;
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				result = s.CreateQuery(queryString).SetCacheable(true).List();
  				Assert.That(result.Count, Is.EqualTo(1));
  				tx.Commit();
  			}
  
  			Assert.That(qs.CacheHitCount, Is.EqualTo(0));
  
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				result = s.CreateQuery(queryString).SetCacheable(true).List();
  				Assert.That(result.Count, Is.EqualTo(1));
  				tx.Commit();
  			}
  
  			Assert.That(qs.CacheHitCount, Is.EqualTo(1));
  			Assert.That(es.FetchCount, Is.EqualTo(0));
  
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				result = s.CreateQuery(queryString).SetCacheable(true).List();
  				Assert.That(result.Count, Is.EqualTo(1));
  				Assert.That(NHibernateUtil.IsInitialized(result[0]));
  				var i = (Item)result[0];
  				i.Name = "Widget";
  				tx.Commit();
  			}
  
  			Assert.That(qs.CacheHitCount, Is.EqualTo(2));
  			Assert.That(qs.CacheMissCount, Is.EqualTo(2));
  			Assert.That(es.FetchCount, Is.EqualTo(0));
  
  			Thread.Sleep(200);
  
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				s.CreateQuery(queryString).SetCacheable(true).List();
  
  				var i = s.Get<Item>(savedId);
  				Assert.That(i.Name, Is.EqualTo("Widget"));
  
  				s.Delete(i);
  				tx.Commit();
  			}
  
  			Assert.That(qs.CacheHitCount, Is.EqualTo(2));
  			Assert.That(qs.CacheMissCount, Is.EqualTo(3));
  			Assert.That(qs.CachePutCount, Is.EqualTo(3));
  			Assert.That(qs.ExecutionCount, Is.EqualTo(3));
  			Assert.That(es.FetchCount, Is.EqualTo(0)); //check that it was being cached
  		}
  
  		private object CreateItem(string queryString)
  		{
  			object savedId;
  			using (ISession s = OpenSession())
  			using (ITransaction tx = s.BeginTransaction())
  			{
  				s.CreateQuery(queryString).SetCacheable(true).List();
  				var i = new Item { Name = "widget" };
  
gt: 				savedId = s.Save(i);