Skip to content

Commit 8721725

Browse files
committed
RDBC-1021: raise ValueError when includes are used in a no_tracking session
session.load(..., includes=...) and query.include() silently discarded includes when no_tracking=True, giving callers a false sense of correctness. C# raises 'Cannot register includes when NoTracking is enabled'. Added the guard to both the load() path and the query _include() method. Regression test: test_no_tracking_includes_guard.py verifies that include calls raise ValueError on no-tracking sessions for both load and query paths.
1 parent 4cd66c4 commit 8721725

3 files changed

Lines changed: 80 additions & 0 deletions

File tree

ravendb/documents/session/document_session.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ def load(
315315
result = load_operation.get_documents(object_type)
316316
return result.popitem()[1] if len(result) == 1 else result if result else None
317317

318+
if self.no_tracking:
319+
raise ValueError(
320+
"Cannot use includes in a no_tracking session "
321+
"(NoTracking is enabled — tracking is required to cache included documents)"
322+
)
323+
318324
include_builder = IncludeBuilder(self.conventions)
319325
includes(include_builder)
320326

ravendb/documents/session/query.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ def __action():
368368
return MoreLikeThisScope(token, self.__add_query_parameter, __action)
369369

370370
def _include(self, path_or_include_builder: Union[str, IncludeBuilderBase]) -> None:
371+
if self._the_session is not None and self._the_session.no_tracking:
372+
raise ValueError(
373+
"Cannot use includes in a no_tracking session "
374+
"(NoTracking is enabled — tracking is required to cache included documents)"
375+
)
371376
if isinstance(path_or_include_builder, str):
372377
self._document_includes.add(path_or_include_builder)
373378
elif isinstance(path_or_include_builder, IncludeBuilderBase):
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""
2+
No-tracking session: using includes raises when session.no_tracking is True.
3+
4+
C# reference: SlowTests/Issues/RavenDB_21339.cs
5+
Using_Includes_In_Non_Tracking_Session_Should_Throw
6+
"""
7+
8+
from ravendb.documents.session.misc import SessionOptions
9+
from ravendb.tests.test_base import TestBase
10+
11+
12+
class Manager:
13+
def __init__(self, name: str = None):
14+
self.name = name
15+
16+
17+
class Employee:
18+
def __init__(self, name: str = None, manager_id: str = None):
19+
self.name = name
20+
self.manager_id = manager_id
21+
22+
23+
class TestRavenDB21339(TestBase):
24+
def setUp(self):
25+
super().setUp()
26+
27+
def _populate(self):
28+
with self.store.open_session() as session:
29+
session.store(Manager(name="Boss"), "managers/1")
30+
session.store(Employee(name="Alice", manager_id="managers/1"), "employees/1")
31+
session.save_changes()
32+
33+
def test_load_with_includes_in_no_tracking_session_should_throw(self):
34+
"""
35+
session.load() with an include builder in a no_tracking session must
36+
raise an exception, not silently ignore the includes."""
37+
self._populate()
38+
39+
with self.store.open_session(session_options=SessionOptions(no_tracking=True)) as session:
40+
with self.assertRaises(Exception) as ctx:
41+
session.load(
42+
"employees/1",
43+
Employee,
44+
includes=lambda b: b.include_documents("manager_id"),
45+
)
46+
self.assertIn("NoTracking", str(ctx.exception))
47+
48+
def test_query_with_include_in_no_tracking_session_should_throw(self):
49+
"""
50+
query.include() in a no_tracking session must raise an exception,
51+
not silently add the include to an unused tracking cache."""
52+
self._populate()
53+
54+
with self.store.open_session(session_options=SessionOptions(no_tracking=True)) as session:
55+
with self.assertRaises(Exception) as ctx:
56+
list(session.query(object_type=Employee).include("manager_id").wait_for_non_stale_results())
57+
self.assertIn("NoTracking", str(ctx.exception))
58+
59+
def test_document_query_with_include_in_no_tracking_session_should_throw(self):
60+
"""
61+
C# spec: session.Advanced.DocumentQuery<Product>().Include(x => x.Supplier).ToList()
62+
in a no_tracking session must raise InvalidOperationException.
63+
"""
64+
self._populate()
65+
66+
with self.store.open_session(session_options=SessionOptions(no_tracking=True)) as session:
67+
with self.assertRaises(Exception) as ctx:
68+
list(session.advanced.document_query(object_type=Employee).include("manager_id"))
69+
self.assertIn("NoTracking", str(ctx.exception))

0 commit comments

Comments
 (0)