Skip to content

Commit 8991b3e

Browse files
committed
Add support for caching fetched relations with Criteria
1 parent 95d38c1 commit 8991b3e

File tree

17 files changed

+744
-78
lines changed

17 files changed

+744
-78
lines changed

src/NHibernate.DomainModel/Northwind/Entities/Northwind.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ public IQueryable<Role> Role
9494
get { return _session.Query<Role>(); }
9595
}
9696

97-
public IEnumerable<IUser> IUsers
97+
public IQueryable<IUser> IUsers
9898
{
9999
get { return _session.Query<IUser>(); }
100100
}
101101
}
102-
}
102+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using NHibernate.Linq;
5+
6+
namespace NHibernate.DomainModel.Northwind.Entities
7+
{
8+
public class NorthwindQueryOver
9+
{
10+
private readonly ISession _session;
11+
12+
public NorthwindQueryOver(ISession session)
13+
{
14+
_session = session;
15+
}
16+
17+
public IQueryOver<Customer, Customer> Customers
18+
{
19+
get { return _session.QueryOver<Customer>(); }
20+
}
21+
22+
public IQueryOver<Product, Product> Products
23+
{
24+
get { return _session.QueryOver<Product>(); }
25+
}
26+
27+
public IQueryOver<Shipper, Shipper> Shippers
28+
{
29+
get { return _session.QueryOver<Shipper>(); }
30+
}
31+
32+
public IQueryOver<Order, Order> Orders
33+
{
34+
get { return _session.QueryOver<Order>(); }
35+
}
36+
37+
public IQueryOver<OrderLine, OrderLine> OrderLines
38+
{
39+
get { return _session.QueryOver<OrderLine>(); }
40+
}
41+
42+
public IQueryOver<Employee, Employee> Employees
43+
{
44+
get { return _session.QueryOver<Employee>(); }
45+
}
46+
47+
public IQueryOver<ProductCategory, ProductCategory> Categories
48+
{
49+
get { return _session.QueryOver<ProductCategory>(); }
50+
}
51+
52+
public IQueryOver<Timesheet, Timesheet> Timesheets
53+
{
54+
get { return _session.QueryOver<Timesheet>(); }
55+
}
56+
57+
public IQueryOver<Animal, Animal> Animals
58+
{
59+
get { return _session.QueryOver<Animal>(); }
60+
}
61+
62+
public IQueryOver<Mammal, Mammal> Mammals
63+
{
64+
get { return _session.QueryOver<Mammal>(); }
65+
}
66+
67+
public IQueryOver<User, User> Users
68+
{
69+
get { return _session.QueryOver<User>(); }
70+
}
71+
72+
public IQueryOver<PatientRecord, PatientRecord> PatientRecords
73+
{
74+
get { return _session.QueryOver<PatientRecord>(); }
75+
}
76+
77+
public IQueryOver<State, State> States
78+
{
79+
get { return _session.QueryOver<State>(); }
80+
}
81+
82+
public IQueryOver<Patient, Patient> Patients
83+
{
84+
get { return _session.QueryOver<Patient>(); }
85+
}
86+
87+
public IQueryOver<Physician, Physician> Physicians
88+
{
89+
get { return _session.QueryOver<Physician>(); }
90+
}
91+
92+
public IQueryOver<Role, Role> Role
93+
{
94+
get { return _session.QueryOver<Role>(); }
95+
}
96+
97+
public IQueryOver<IUser, IUser> IUsers
98+
{
99+
get { return _session.QueryOver<IUser>(); }
100+
}
101+
}
102+
}
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Linq;
12+
using NHibernate.Cfg;
13+
using NHibernate.DomainModel.Northwind.Entities;
14+
using NUnit.Framework;
15+
16+
namespace NHibernate.Test.Criteria.ReadonlyTests
17+
{
18+
using System.Threading.Tasks;
19+
[TestFixture]
20+
public class QueryOverCacheableTestsAsync : CriteriaNorthwindReadonlyTestCase
21+
{
22+
//Just for discoverability
23+
private class CriteriaCacheableTest{}
24+
25+
protected override void Configure(Configuration cfg)
26+
{
27+
cfg.SetProperty(Environment.UseQueryCache, "true");
28+
cfg.SetProperty(Environment.GenerateStatistics, "true");
29+
base.Configure(cfg);
30+
}
31+
32+
[Test]
33+
public async Task QueryIsCacheableAsync()
34+
{
35+
Sfi.Statistics.Clear();
36+
await (Sfi.EvictQueriesAsync());
37+
38+
var x = await (db.Customers.Cacheable().ListAsync());
39+
var x2 = await (db.Customers.Cacheable().ListAsync());
40+
41+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(1), "Unexpected execution count");
42+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(1), "Unexpected cache put count");
43+
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(1), "Unexpected cache hit count");
44+
}
45+
46+
[Test]
47+
public async Task QueryIsCacheable2Async()
48+
{
49+
Sfi.Statistics.Clear();
50+
await (Sfi.EvictQueriesAsync());
51+
52+
var x = await (db.Customers.Cacheable().ListAsync());
53+
var x2 = await (db.Customers.ListAsync());
54+
55+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(2), "Unexpected execution count");
56+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(1), "Unexpected cache put count");
57+
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(0), "Unexpected cache hit count");
58+
}
59+
60+
[Test]
61+
public async Task QueryIsCacheableWithRegionAsync()
62+
{
63+
Sfi.Statistics.Clear();
64+
await (Sfi.EvictQueriesAsync());
65+
await (Sfi.EvictQueriesAsync("test"));
66+
await (Sfi.EvictQueriesAsync("other"));
67+
68+
var x = await (db.Customers.Cacheable().CacheRegion("test").ListAsync());
69+
var x2 = await (db.Customers.Cacheable().CacheRegion("test").ListAsync());
70+
var x3 = await (db.Customers.Cacheable().CacheRegion("other").ListAsync());
71+
72+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(2), "Unexpected execution count");
73+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2), "Unexpected cache put count");
74+
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(1), "Unexpected cache hit count");
75+
}
76+
77+
78+
[Test]
79+
public async Task CanBeCombinedWithFetchAsync()
80+
{
81+
82+
Sfi.Statistics.Clear();
83+
await (Sfi.EvictQueriesAsync());
84+
85+
await (db.Customers
86+
.Cacheable()
87+
.ListAsync());
88+
89+
await (db.Orders
90+
.Cacheable()
91+
.ListAsync());
92+
93+
await (db.Customers
94+
.Fetch(SelectMode.Fetch, x => x.Orders)
95+
.Cacheable()
96+
.ListAsync());
97+
98+
await (db.Orders
99+
.Fetch(SelectMode.Fetch, x => x.OrderLines)
100+
.Cacheable()
101+
.ListAsync());
102+
103+
var customer = await (db.Customers
104+
.Fetch(SelectMode.Fetch, x => x.Address)
105+
.Where(x => x.CustomerId == "VINET")
106+
.Cacheable()
107+
.SingleOrDefaultAsync());
108+
109+
customer = await (db.Customers
110+
.Fetch(SelectMode.Fetch, x => x.Address)
111+
.Where(x => x.CustomerId == "VINET")
112+
.Cacheable()
113+
.SingleOrDefaultAsync());
114+
115+
Assert.That(NHibernateUtil.IsInitialized(customer.Address), Is.True, "Expected the fetched Address to be initialized");
116+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(5), "Unexpected execution count");
117+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(5), "Unexpected cache put count");
118+
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(1), "Unexpected cache hit count");
119+
}
120+
121+
[Test]
122+
public async Task FetchIsCacheableAsync()
123+
{
124+
Sfi.Statistics.Clear();
125+
await (Sfi.EvictQueriesAsync());
126+
127+
Order order;
128+
order = (await (db.Orders
129+
.Fetch(
130+
SelectMode.Fetch,
131+
x => x.Customer,
132+
x => x.OrderLines,
133+
x => x.OrderLines.First().Product,
134+
x => x.OrderLines.First().Product.OrderLines)
135+
.Where(x => x.OrderId == 10248)
136+
.Cacheable()
137+
.ListAsync()))
138+
.First();
139+
140+
AssertFetchedOrder(order);
141+
142+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(1), "Unexpected execution count");
143+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(1), "Unexpected cache put count");
144+
Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(1), "Unexpected cache miss count");
145+
146+
Sfi.Statistics.Clear();
147+
Session.Clear();
148+
149+
order = (await (db.Orders
150+
.Fetch(
151+
SelectMode.Fetch,
152+
x => x.Customer,
153+
x => x.OrderLines,
154+
x => x.OrderLines.First().Product,
155+
x => x.OrderLines.First().Product.OrderLines)
156+
.Where(x => x.OrderId == 10248)
157+
.Cacheable()
158+
.ListAsync()))
159+
.First();
160+
161+
AssertFetchedOrder(order);
162+
163+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(0), "Unexpected execution count");
164+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(0), "Unexpected cache put count");
165+
Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(0), "Unexpected cache miss count");
166+
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(1), "Unexpected cache hit count");
167+
}
168+
169+
[Test]
170+
public async Task FutureFetchIsCacheableAsync()
171+
{
172+
Sfi.Statistics.Clear();
173+
await (Sfi.EvictQueriesAsync());
174+
var multiQueries = Sfi.ConnectionProvider.Driver.SupportsMultipleQueries;
175+
176+
Order order;
177+
178+
db.Orders
179+
.Fetch(SelectMode.Fetch, x => x.Customer)
180+
.Where(x => x.OrderId == 10248)
181+
.Cacheable()
182+
.Future();
183+
184+
order = db.Orders
185+
.Fetch(
186+
SelectMode.Fetch,
187+
x => x.OrderLines,
188+
x => x.OrderLines.First().Product,
189+
x => x.OrderLines.First().Product.OrderLines)
190+
.Where(x => x.OrderId == 10248)
191+
.Cacheable()
192+
.Future()
193+
.ToList()
194+
.First();
195+
196+
AssertFetchedOrder(order);
197+
198+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(multiQueries ? 1 : 2), "Unexpected execution count");
199+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(2), "Unexpected cache put count");
200+
Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(2), "Unexpected cache miss count");
201+
202+
Sfi.Statistics.Clear();
203+
Session.Clear();
204+
205+
db.Orders
206+
.Fetch(SelectMode.Fetch, x => x.Customer)
207+
.Where(x => x.OrderId == 10248)
208+
.Cacheable()
209+
.Future();
210+
211+
order = db.Orders
212+
.Fetch(
213+
SelectMode.Fetch,
214+
x => x.OrderLines,
215+
x => x.OrderLines.First().Product,
216+
x => x.OrderLines.First().Product.OrderLines)
217+
.Where(x => x.OrderId == 10248)
218+
.Cacheable()
219+
.Future()
220+
.ToList()
221+
.First();
222+
223+
AssertFetchedOrder(order);
224+
225+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(0), "Unexpected execution count");
226+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(0), "Unexpected cache put count");
227+
Assert.That(Sfi.Statistics.QueryCacheMissCount, Is.EqualTo(0), "Unexpected cache miss count");
228+
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(2), "Unexpected cache hit count");
229+
}
230+
231+
private static void AssertFetchedOrder(Order order)
232+
{
233+
Assert.That(NHibernateUtil.IsInitialized(order.Customer), Is.True, "Expected the fetched Customer to be initialized");
234+
Assert.That(NHibernateUtil.IsInitialized(order.OrderLines), Is.True, "Expected the fetched OrderLines to be initialized");
235+
Assert.That(order.OrderLines, Has.Count.EqualTo(3), "Expected the fetched OrderLines to have 3 items");
236+
var orderLine = order.OrderLines.First();
237+
Assert.That(NHibernateUtil.IsInitialized(orderLine.Product), Is.True, "Expected the fetched Product to be initialized");
238+
Assert.That(NHibernateUtil.IsInitialized(orderLine.Product.OrderLines), Is.True, "Expected the fetched OrderLines to be initialized");
239+
}
240+
}
241+
}

0 commit comments

Comments
 (0)