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
}
Starting from DataObjects.Net 4.4 ‘Automatic Session activation’ and ‘Automatic Transaction opening’ modes made optional, moreover, they are 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);
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)) {
// ...
}
Note
This chapter describes session particularities in DataObjects.Net 4.3 and DataObjects.Net 4.4 with SessionProfile=Legacy.
Session class implements IContext interface, it means that a session can be either active or not active in particular thread. Each thread 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.