Evict a Single Entity from a Session
-
By default, the session tracks all entities that it has either stored, loaded, or queried.
Any changes made to these entities are automatically persisted whenSaveChangesis called. -
Use the
Evictmethod to remove a specific entity from the session's tracking before calling SaveChanges.
Eviction stops the session from tracking the entity, removes it from the identity map and internal cache,
and cancels any pending operations for that entity (e.g., Store, Delete). -
This article explains how to evict a single entity from the session.
To evict all tracked entities and clear all pending operations, use the Clear method instead.
To prevent an entity from being tracked, see DisableTracking. -
In this article:
Evict an entity before saving
- Calling
Evicton an entity that is stored removes it from the session’s tracking and cancels the pending store operation.
As a result, the entity will not be saved to the database when SaveChanges is called. - This can be useful if you’ve staged an entity to be stored, but then decide to discard it before committing changes.
- sync_session
- async_session
using (var session = store.OpenSession())
{
Employee employee1 = new Employee { FirstName = "John", LastName = "Doe" };
Employee employee2 = new Employee { FirstName = "Jane", LastName = "Doe" };
// Store both employees in the session
// The session begins tracking both employee entities
session.Store(employee1, "employees/1");
session.Store(employee2, "employees/2");
// Evict employee1
// This removes employee1 from the session's tracking
// and cancels its pending store operation
session.Advanced.Evict(employee1);
// Only employee2 will be saved
session.SaveChanges();
}
using (var asyncSession = store.OpenAsyncSession())
{
Employee employee1 = new Employee { FirstName = "John", LastName = "Doe" };
Employee employee2 = new Employee { FirstName = "Jane", LastName = "Doe" };
// Store both employees in the session
// The session begins tracking both employee entities
await asyncSession.StoreAsync(employee1, "employees/1");
await asyncSession.StoreAsync(employee2, "employees/2");
// Evict employee1
// This removes employee1 from the session's tracking
// and cancels its pending store operation
asyncSession.Advanced.Evict(employee1);
// Only employee2 will be saved
asyncSession.SaveChangesAsync();
}
Evict an entity to force reload from server
- Calling
Evicton an entity that was previously loaded removes it from the session’s tracking.
The next time you call Load for that entity, RavenDB will fetch it from the server instead of returning the cached version. - This can be useful if you want to ensure you're working with the latest version of a document,
for example, if you expect the document was modified outside the session.
- sync_session
- async_session
using (var session = store.OpenSession())
{
// Load an entity from the server
// The session begins tracking the loaded entity
Employee employee = session.Load<Employee>("employees/1");
Console.WriteLine("number of requests = " + session.Advanced.NumberOfRequests); // 1
// Loading the same entity again does NOT trigger a server call
employee = session.Load<Employee>("employees/1");
Console.WriteLine("number of requests = " + session.Advanced.NumberOfRequests); // 1
// Evict the entity
// This removes it from the session's tracking
session.Advanced.Evict(employee);
// Loading the entity now DOES trigger a server call
employee = session.Load<Employee>("employees/1");
Console.WriteLine("number of requests = " + session.Advanced.NumberOfRequests); // 2
}
using (var asyncSession = store.OpenAsyncSession())
{
// Load an entity from the server
// The session begins tracking the loaded entity
Employee employee = await asyncSession.LoadAsync<Employee>("employees/1");
Console.WriteLine("number of requests = " + session.Advanced.NumberOfRequests); // 1
// Loading the same entity again does NOT trigger a server call
employee = await asyncSession.LoadAsync<Employee>("employees/1");
Console.WriteLine("number of requests = " + session.Advanced.NumberOfRequests); // 1
// Evict the entity
// This removes it from the session's tracking
asyncSession.Advanced.Evict(employee);
// Loading the entity now DOES trigger a server call
employee = await asyncSession.LoadAsync<Employee>("employees/1");
Console.WriteLine("number of requests = " + session.Advanced.NumberOfRequests); // 2
}
Evict an entity from the session's delete queue
- Calling
Evicton an entity that was previously marked for deletion removes it from the session's delete queue.
As a result, the deletion will not be sent to the server when SaveChanges is called. - This can be useful if you need to revert a pending deletion before committing changes.
- sync_session
- async_session
using (var session = store.OpenSession())
{
var employee1 = session.Load<Employee>("employees/1");
var employee2 = session.Load<Employee>("employees/2");
// Mark both employees for deletion
session.Delete(employee1);
session.Delete(employee1);
// Remove employee1 from tracking and from delete queue
session.Advanced.Evict(employee1);
// Only employee2 will be deleted
session.SaveChanges();
}
using (var asyncSession = store.OpenAsyncSession())
{
var employee1 = await asyncSession.LoadAsync<Employee>("employees/1");
var employee2 = await asyncSession.LoadAsync<Employee>("employees/2");
// Mark both employees for deletion
asyncSession.Delete(employee1);
asyncSession.Delete(employee2);
// Remove employee1 from tracking and from delete queue
asyncSession.Advanced.Evict(employee1);
// Only employee2 will be deleted
await asyncSession.SaveChangesAsync();
}
Limitations
Evictcannot be called from within an OnBeforeStore or OnBeforeDelete event handler.
Attempting to do so will throw an exception.- This is a design limitation intended to prevent changes to the session's internal state during event handlers that are triggered by SaveChanges. For example:
- sync_session
- async_session
using (var session = store.OpenSession())
{
session.Store(new Employee() { FirstName = "Foo1" }, "employees/1");
session.Store(new Employee() { FirstName = "Foo2" }, "employees/2");
session.SaveChanges();
}
using (var session = store.OpenSession())
{
var employee2 = session.Load<Employee>("employees/2");
// Register an event handler that will be called before any document is saved during SaveChanges
session.Advanced.OnBeforeStore += delegate (object sender, BeforeStoreEventArgs args)
{
try
{
args.Session.Evict(employee2);
}
catch (InvalidOperationException e)
{
// An exception is thrown:
// "Cannot Evict entity during OnBeforeStore..."
}
};
session.Store(new Employee { FirstName = "Foo3" }, "employees/3");
// SaveChanges triggers the 'OnBeforeStore' event
session.SaveChanges();
}
using (var session = store.OpenSession())
{
var employee2 = session.Load<Employee>("employees/2");
// Register an event handler that will be called before any document is deleted during SaveChanges
session.Advanced.OnBeforeDelete += delegate (object sender, BeforeDeleteEventArgs args)
{
try
{
args.Session.Evict(employee2);
}
catch (InvalidOperationException e)
{
// An exception is thrown:
// "Cannot Evict entity during OnBeforeDelete..."
}
};
// Load employees/1 and mark it for deletion
var employee1 = session.Load<Employee>("employees/1");
session.Delete(employee1);
// SaveChanges triggers the OnBeforeDelete event
session.SaveChanges();
}
using (var asyncSession = store.OpenAsyncSession())
{
await asyncSession.StoreAsync(new Employee { FirstName = "Foo1" }, "employees/1");
await asyncSession.StoreAsync(new Employee { FirstName = "Foo2" }, "employees/2");
await asyncSession.SaveChangesAsync();
}
using (var asyncSession = store.OpenAsyncSession())
{
var employee2 = await asyncSession.LoadAsync<Employee>("employees/2");
// Register an event handler that will be called before any document is saved during SaveChangesAsync
asyncSession.Advanced.OnBeforeStore += async (sender, args) =>
{
try
{
args.Session.Evict(employee2);
}
catch (InvalidOperationException e)
{
// An exception is thrown:
// "Cannot Evict entity during OnBeforeStore..."
}
};
await asyncSession.StoreAsync(new Employee { FirstName = "Foo3" }, "employees/3");
// SaveChangesAsync triggers the OnBeforeStore event
await asyncSession.SaveChangesAsync();
}
using (var asyncSession = store.OpenAsyncSession())
{
var employee2 = await asyncSession.LoadAsync<Employee>("employees/2");
// Register an event handler that will be called before any document is deleted during SaveChangesAsync
asyncSession.Advanced.OnBeforeDelete += async (sender, args) =>
{
try
{
args.Session.Evict(employee2);
}
catch (InvalidOperationException e)
{
// An exception is thrown:
// "Cannot Evict entity during OnBeforeDelete..."
}
};
// Load employees/1 and mark it for deletion
var employee1 = await asyncSession.LoadAsync<Employee>("employees/1");
asyncSession.Delete(employee1);
// SaveChangesAsync triggers the OnBeforeDelete event
await asyncSession.SaveChangesAsync();
}
Syntax
void Evict<T>(T entity);
| Parameter | Type | Description |
|---|---|---|
| T | T | Type of the entity to evict |
| entity | T | Instance of the entity to evict from tracking |