In an application there are often multiple operations running at the same time. A typical example is a web application which processes multiple requests at the same time. These operations should be isolated from each other. This means that for the database we want to have multiple transactions at the same time. Each transaction does some work and other transactions shouldn't interfere .
db4o supports this scenario with session containers. A session container is a lightweight object-container with its own transaction and reference cache, but shares the resources with its parent container. That means you can commit and rollback changes on such a session container without disturbing the work of other session containers. If you want to implement units of work, you might considers using a session container for each unit. You can create such a container with the open session call.
using (IObjectContainer rootContainer = Db4oEmbedded.OpenFile(DatabaseFileName)) { // open the db4o-session. For example at the beginning for a web-request using (IObjectContainer session = rootContainer.Ext().OpenSession()) { // do the operations on the session-container session.Store(new Person("Joe")); } }
Using rootContainer As IObjectContainer = Db4oEmbedded.OpenFile(DatabaseFileName) ' open the db4o-session. For example at the beginning for a web-request Using session As IObjectContainer = rootContainer.Ext().OpenSession() ' do the operations on the session-container session.Store(New Person("Joe")) End Using End Using
As previously mentioned session-containers are isolated from each other. Each session container has its own transaction and its own reference system. This isolation ensures that the different session container don't interfere witch each other.
They don't share the objects loaded and stored with each other. That means you need to load and store the a object with the same session container. When you try to load a object form one session-container and store it with another, you well end up with two separate copies of that object.
Since the transactions are isolated, changes are only visible for other session containers when you've committed. Before the commit call the changes are not visible to other session containers.
session1.Store(new Person("Joe")); session1.Store(new Person("Joanna")); // the second session won't see the changes until the changes are committed PrintAll(session2.Query<Person>()); session1.Commit(); // new the changes are visiable for the second session PrintAll(session2.Query<Person>());
session1.Store(New Person("Joe")) session1.Store(New Person("Joanna")) ' the second session won't see the changes until the changes are committed PrintAll(session2.Query(Of Person)()) session1.Commit() ' new the changes are visiable for the second session PrintAll(session2.Query(Of Person)())
Note also that sessions also have their own reference cache. So when a object is already loaded, it wont be refreshed if another transaction updates the object. You explicitly need to refresh it.
Person personOnSession1 = session1.Query<Person>()[0]; Person personOnSession2 = session2.Query<Person>()[0]; personOnSession1.Name = "NewName"; session1.Store(personOnSession1); session1.Commit(); // the second session still sees the old value, because it was cached Console.WriteLine(personOnSession2.Name); // you can explicitly refresh it session2.Ext().Refresh(personOnSession2,int.MaxValue); Console.WriteLine(personOnSession2.Name);
Dim personOnSession1 As Person = session1.Query(Of Person)()(0) Dim personOnSession2 As Person = session2.Query(Of Person)()(0) personOnSession1.Name = "NewName" session1.Store(personOnSession1) session1.Commit() ' the second session still sees the old value, because it was cached Console.WriteLine(personOnSession2.Name) ' you can explicitly refresh it session2.Ext().Refresh(personOnSession2, Integer.MaxValue) Console.WriteLine(personOnSession2.Name)