<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns:MadCap="http://www.madcapsoftware.com/Schemas/MadCap.xsd" MadCap:lastBlockDepth="2" MadCap:lastHeight="120" MadCap:lastWidth="624" MadCap:disableMasterStylesheet="true" MadCap:tocPath="Advanced Features|Callbacks|Possible Usecases" MadCap:InPreviewMode="false" MadCap:RuntimeFileType="Topic" MadCap:TargetType="WebHelp" MadCap:PathToHelpSystem="../../../../" MadCap:HelpSystemFileName="index.xml" MadCap:SearchType="Stem"> <head><title>Autoincrement </title> <script type="text/javascript">/* <![CDATA[ */ window.onload = function(){ var pathToFlash = $('html').attr('MadCap:PathToHelpSystem') + 'Content/Resources/Code/ZeroClipboard.swf'; ZeroClipboard.setMoviePath(pathToFlash); function bindToClipBord(element,content){ var clip = new ZeroClipboard.Client(); clip.setText(content); clip.glue(element); }; if(location.protocol==='file:'){ $('.copylink-marker').remove(); } else{ $('.copylink-marker').each(function(){ var text = $(this).parent().parent().children('.prettyprint').html(); $(this).hover(function(){ bindToClipBord(this,text); }, function(){}); }); } prettyPrint(); }; /* ]]> */</script> <link href="../../../SkinSupport/MadCap.css" rel="stylesheet" /> <link href="../../../Resources/Stylesheets/OnlineStyle.css" rel="stylesheet" /> <script src="../../../SkinSupport/MadCapAll.js"> </script> <script src="../../../Resources/Code/prettify.js"> </script> <script src="../../../Resources/Code/lang-vb.js"> </script> <script src="../../../Resources/Code/jquery.min.js"> </script> <script src="../../../Resources/Code/ZeroClipboard.js"> </script> </head> <body> <p class="MCWebHelpFramesetLink" style="display: none;"><a href="../../../../index_CSH.html#advanced_topics/callbacks/possible_usecases/autoincrement.htm" style="">Open topic with navigation</a> </p> <div class="MCBreadcrumbsBox"><span class="MCBreadcrumbsPrefix">You are here: </span><a class="MCBreadcrumbsLink" href="../../../advanced_topics.htm">Advanced Features</a><span class="MCBreadcrumbsDivider"> > </span><a class="MCBreadcrumbsLink" href="../../callbacks.htm">Callbacks</a><span class="MCBreadcrumbsDivider"> > </span><a class="MCBreadcrumbsLink" href="../possible_usecases.htm">Possible Usecases</a><span class="MCBreadcrumbsDivider"> > </span><span class="MCBreadcrumbs">Autoincrement</span> </div> <p> <script type="text/javascript">/*<![CDATA[*/document.write('<a href="' + location.href +'">'); document.write("Direct Link"); document.write('</a>');/*]]>*/</script> </p> <p> </p> <h1><a name="kanchor82"></a>Autoincrement</h1> <p>db4o does not deliver a field auto increment feature, which is common in <span class="MCTextPopup"><a href="javascript:void(0);" class="MCTextPopupSpot" onclick="FMCTextPopup( event, this ); return false;">RDBMS<img style="border: none;margin-left: 5px;" src="../../../SkinSupport/ExpandingClosed.gif" MadCap:altsrc="../../../SkinSupport/ExpandingOpen.gif" class="MCExpandingIcon" onload="if ( typeof( FMCPreloadImage ) == 'function' ) { FMCPreloadImage( '../../../SkinSupport/ExpandingOpen.gif' ); }" /></a><span class="MCTextPopupBody" style="display: none; ">Relational Database Management System</span></span>. Normally you don't need any additional ids, since db4o manages objects by object-identity. However cases where you have <a href="../../../platform_specific_issues/disconnected_objects.htm">disconnected objects</a>, you need additional ids. One of then possibilities it to use auto incremented ids.</p> <p> If your application logic requires this feature you can implement it using external callbacks. One of the possible solutions is presented below. Note that this example only works in embedded-mode.</p> <p>This example assumes that all object which need an auto incremented id are subclasses of the IDHolder-class. This class contains the auto-incremented id.</p> <div class="codesnippet" MadCap:conditions="Primary.c#"> <pre class="prettyprint" xml:space="preserve">private int id; public int Id { get { return id; } set { id = value; } } </pre> <div class="codesnippet-meta">IDHolder.cs: id holder <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-csharp.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <div class="codesnippet" MadCap:conditions="Primary.VB.NET"> <pre class="prettyprint lang-vb" MadCap:conditions="Primary.Online" xml:space="preserve">Private m_id As Integer Public Property Id() As Integer Get Return m_id End Get Set(ByVal value As Integer) m_id = value End Set End Property </pre> <div class="codesnippet-meta">IDHolder.vb: id holder <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-vb.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <p>First create a class which keeps the state of the auto-increment numbers. For example a map which keeps the latest auto incremented id for each class.</p> <div class="codesnippet" MadCap:conditions="Primary.c#"> <pre class="prettyprint" xml:space="preserve">private class PersistedAutoIncrements { private readonly IDictionary<Type, int> currentHighestIds = new Dictionary<Type, int>(); public int NextNumber(Type forClass) { int number; if (!currentHighestIds.TryGetValue(forClass, out number)) { number = 0; } number += 1; currentHighestIds[forClass] = number; return number; } } </pre> <div class="codesnippet-meta">AutoIncrement.cs: persistent auto increment <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-csharp.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <div class="codesnippet" MadCap:conditions="Primary.VB.NET"> <pre class="prettyprint lang-vb" MadCap:conditions="Primary.Online" xml:space="preserve">Private Class PersistedAutoIncrements Private ReadOnly currentHighestIds As IDictionary(Of Type, Integer) _ = New Dictionary(Of Type, Integer)() Public Function NextNumber(ByVal forClass As Type) As Integer Dim number As Integer If Not currentHighestIds.TryGetValue(forClass, number) Then number = 0 End If number += 1 currentHighestIds(forClass) = number Return number End Function End Class </pre> <div class="codesnippet-meta">AutoIncrement.vb: persistent auto increment <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-vb.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <p>Then create two methods, which are called later. One which returns the next auto-incremented id for a certain class. Another which stores the current state of the auto-increments.</p> <div class="codesnippet" MadCap:conditions="Primary.c#"> <pre class="prettyprint" xml:space="preserve">public int GetNextID(Type forClass) { lock (dataLock) { PersistedAutoIncrements incrementState = EnsureLoadedIncrements(); return incrementState.NextNumber(forClass); } } public void StoreState() { lock (dataLock) { if (null != state) { container.Ext().Store(state,2); } } } </pre> <div class="codesnippet-meta">AutoIncrement.cs: getting the next id and storing state <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-csharp.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <div class="codesnippet" MadCap:conditions="Primary.VB.NET"> <pre class="prettyprint lang-vb" MadCap:conditions="Primary.Online" xml:space="preserve">Public Function GetNextID(ByVal forClass As Type) As Integer SyncLock dataLock Dim incrementState As PersistedAutoIncrements = EnsureLoadedIncrements() Return incrementState.NextNumber(forClass) End SyncLock End Function Public Sub StoreState() SyncLock dataLock If state IsNot Nothing Then container.Ext().Store(state, 2) End If End SyncLock End Sub </pre> <div class="codesnippet-meta">AutoIncrement.vb: getting the next id and storing state <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-vb.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <p>The last part is to ensure that the existing auto-increments are loaded from the database. Or if not existing a new instance is created.</p> <div class="codesnippet" MadCap:conditions="Primary.c#"> <pre class="prettyprint" xml:space="preserve">private PersistedAutoIncrements EnsureLoadedIncrements() { if (null == state) { state = LoadOrCreateState(); } return state; } private PersistedAutoIncrements LoadOrCreateState() { IList<PersistedAutoIncrements> existingState = container.Query<PersistedAutoIncrements>(); if (0 == existingState.Count) { return new PersistedAutoIncrements(); } else if (1 == existingState.Count) { return existingState[0]; } else { throw new InvalidOperationException("Cannot have more than one state stored in database"); } } </pre> <div class="codesnippet-meta">AutoIncrement.cs: load the state from the database <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-csharp.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <div class="codesnippet" MadCap:conditions="Primary.VB.NET"> <pre class="prettyprint lang-vb" MadCap:conditions="Primary.Online" xml:space="preserve">Private Function EnsureLoadedIncrements() As PersistedAutoIncrements If state Is Nothing Then state = LoadOrCreateState() End If Return state End Function Private Function LoadOrCreateState() As PersistedAutoIncrements Dim existingState As IList(Of PersistedAutoIncrements) = container.Query(Of PersistedAutoIncrements)() If 0 = existingState.Count Then Return New PersistedAutoIncrements() ElseIf 1 = existingState.Count Then Return existingState(0) Else Throw New InvalidOperationException("Cannot have more than one state stored in database") End If End Function </pre> <div class="codesnippet-meta">AutoIncrement.vb: load the state from the database <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-vb.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <p>Now it's time to use the callbacks. Every time when a new object is created, assign a new id. For this the creating-event is perfect. When commiting also make the auto increment-state persistent, to ensure that no id is used twice.</p> <div class="codesnippet" MadCap:conditions="Primary.c#"> <pre class="prettyprint" xml:space="preserve">AutoIncrement increment = new AutoIncrement(container); IEventRegistry eventRegistry = EventRegistryFactory.ForObjectContainer(container); eventRegistry.Creating+= delegate(object sender, CancellableObjectEventArgs args) { if (args.Object is IDHolder) { IDHolder idHolder = (IDHolder)args.Object; idHolder.Id = increment.GetNextID(idHolder.GetType()); } }; eventRegistry.Committing += delegate(object sender, CommitEventArgs args) { increment.StoreState(); };</pre> <div class="codesnippet-meta">AutoIncrementExample.cs: use events to assign the ids <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-csharp.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <div class="codesnippet" MadCap:conditions="Primary.VB.NET"> <pre class="prettyprint lang-vb" MadCap:conditions="Primary.Online" xml:space="preserve">Dim increment As New AutoIncrement(container) Dim eventRegistry As IEventRegistry = EventRegistryFactory.ForObjectContainer(container) AddHandler eventRegistry.Creating, AddressOf increment.HandleCreating AddHandler eventRegistry.Committing, AddressOf increment.HandleCommiting</pre> <div class="codesnippet-meta">AutoIncrementExample.vb: use events to assign the ids <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-vb.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <p>Last, don't forget to index the id-field. Otherwise looks-ups will be slow.</p> <div class="codesnippet" MadCap:conditions="Primary.c#"> <pre class="prettyprint" xml:space="preserve">configuration.Common.ObjectClass(typeof (IDHolder)).ObjectField("id").Indexed(true);</pre> <div class="codesnippet-meta">AutoIncrementExample.cs: index the id-field <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-csharp.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <div class="codesnippet" MadCap:conditions="Primary.VB.NET"> <pre class="prettyprint lang-vb" MadCap:conditions="Primary.Online" xml:space="preserve">configuration.Common.ObjectClass(GetType(IDHolder)).ObjectField("id").Indexed(True)</pre> <div class="codesnippet-meta">AutoIncrementExample.vb: index the id-field <div class="codedownload"><a href="../../../CodeExamples/disconnectedobj/idexamples/Example-disconnectedobj-idexamples-vb.zip" class="codedownload" MadCap:conditions="Primary.Online">Download Code</a></div><div class="codedownload copylink-marker" MadCap:conditions="Primary.Online"><a href="#copy">Copy Code</a></div></div> </div> <script type="text/javascript" src="../../../SkinSupport/MadCapBodyEnd.js"> </script> </body> </html>