The notion of Session is close to DataContext in ADO.NET Entity Framework.
Key facts about sessions:
Session implements IDisposable interface so it is convenient to use it within using construct.
using (var session = domain.OpenSession()) {
// Work with persistent classes here
}
or
await using (var session = await domain.OpenSessionAsync()) {
// Work with persistent classes here
}
Starting from DataObjects.Net 4.4 ‘Automatic Session activation’ mode made optional, moreover, it is switched off by default. In addition, Session Profile notion is introduced. It represents a combination of predefined session options for particular scenarios.
For now there are three main profiles: Server profile, Client profile & Legacy profile.
Session profile is a combination of SessionOptions values, so we build SessionConfiguration instance using this profile and construct Session afterwards.
var configuration = new SessionConfiguration(
"mySession", SessionOptions.ClientProfile);
using (var session = domain.OpenSession(configuration)) {
// some code
}
In case you want every Session within your Domain runs in a particular profile by default, you can set up Default Session in applicatin configuration file:
<domain upgradeMode="..." connectionUrl="...">
<types>
<add assembly="..."/>
</types>
<sessions>
<session name="Default" options="ClientProfile" />
</sessions>
</domain>
You may achieve the same by setting up Default Session in C# code:
var domainConfiguration = new DomainConfiguration();
var sessionConfiguration = new SessionConfiguration(
"Default", SessionOptions.ClientProfile);
domainConfiguration.Sessions.Add(sessionConfiguration);
var domain = Domain.Build(domainConfiguration);
Here, Session name Default is a name of one of built-in predefined session configurations. When you manually setup a session configuration with name Default, DataObjects.Net uses yours instead of predefined one.
There are other predefined session configurations with following built-in names:
When overriding one of non-Default configuration MAKE SURE you UNDERSTAND what you’re changing. Some of the options are pretty safe to change, like DefaultCommandTimeout, CacheSize, BatchSize, others - can cause problems when changed carelessly, like DefaultIsolationLevel.
Another method overload domain.OpenSession(sessionConfig) accepts SessionConfiguration instance, that contains several session-level options:
Session configuration can be created manually:
var sessionCongfig = new SessionConfiguration {
BatchSize = 25,
DefaultIsolationLevel = IsolationLevel.ReadCommitted,
CacheSize = 1000,
Options = SessionOptions.ServerProfile
};
Or declared and loaded from configuration file:
<domain name="TestDomain"
upgradeMode="Recreate"
connectionUrl="sqlserver://localhost/MyTests" >
<sessions>
<session name="TestSession"
batchSize="25" isolationLevel="ReadCommitted"
cacheSize="1000" options="AutoShortenTransactions" />
</sessions>
</domain>
var domainConfig = DomainConfiguration.Load("TestDomain");
var sessionConfig = domainConfig.Sessions["TestSession"];
When session configuration is created or loaded, session with this configuration can be opened by special Open() method overload:
using (var session = domain.OpenSession(sessionConfig)) {
// ...
}
or
using (var session = await domain.OpenSessionAsync(sessionConfig)) {
// ...
}
Note
This chapter describes session particularities in DataObjects.Net with SessionProfile = Legacy or SessionOption.AutoActivation option turned on. We do not recommend using session activation in applications with paralled or asynchronous execution because it has some caviars and wrong use of it can cause problems.
In DataObjects.Net 6 session activation has changed and uses AsyncLocal instead of ThreadStatic to make session activation compatible with asychronous execution flow.
Session class implements IContext interface, it means that a session can be either active or not active in particular execution flow. In case of synchronous execution this means that active session is bound to one thread. When parallel or asyncronous execution comes to the game active session may be also available to some other threads. This is normal AsyncLocal behavior.
Each execution flow can contain only one active session, that can be a accessed via Session.Current property or Session.Demand() method. When you creates new entitiy or loads it from database, they are automatically bounded to the current session.
New session can be opened and activated by domain.OpenSession() method. In the following example newly opened session is automatically activated within the using block:
using (var session = domain.OpenSession()) {
// creating new entity
var newPerson = new Person();
// fetching entity by its ID
var fetchedPerson = session.Query.Single<Person>(personId);
Console.WriteLine("Our session is current: {0}",
Session.Current == session);
Console.WriteLine("New entity is bound to our session: {0}",
newPerson.Session == session);
Console.WriteLine("Fetched entity is bound to our session: {0}",
fetchedPerson.Session == session);
}
The result will be true in all cases.
Existing session can be activated by Activate() method:
using (session.Activate()) {
// Work with persistent classes here
}
DataObjects.Net provides the following session activation pattern:
Session activation API:
That’s true:
So since all the objects requiring a Session (e.g. Entity, Structure and EntitySet<T>) are SessionBound descendants, almost all of their public methods implicitly activate the Session they’re bound to. This ensures:
You can use Session.Demand() and Session.Current inside their code, or inside any code they invoke.
So e.g. you can invoke static methods without passing the Session to them directly.
Note
Is the session activation technique fast? For example, Session.Activate() always returns an IDisposable object – so does this mean any SessionBound method call allocates something on heap?
No, it doesn’t: actually, Session.Activate() returns a special IDisposable singleton (so-called void scope) doing nothing on its disposal, if this Session is already active. So this is pretty fast process.
Presence of current Session allows us to provide current Domain as well:
Here is actual Domain.Current property code:
public static Domain Current {
get {
var session = Session.Current;
return session != null ? session.Domain : null;
}
}
Session type exposes wide range of events, from Entity-related events to DbCommand events. Session events are accessed through Session.Events property. Unlike ‘event-like’ protected virtual methods in Entity & EntitySet types, session events are preferred in case you don’t have access to source code of the domain model or going to be less invasive and more flexible.