<?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="Basics Operations & Concepts|Update Concept|Transparent Persistence|Transparent Persistence Pitfalls" MadCap:InPreviewMode="false" MadCap:RuntimeFileType="Topic" MadCap:TargetType="WebHelp" MadCap:PathToHelpSystem="../../../../../" MadCap:HelpSystemFileName="index.xml" MadCap:SearchType="Stem"> <head><title>Object Clone </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#basics/update_concept/transparent_persistence/transparent_persistence/object_clone.htm" style="">Open topic with navigation</a> </p> <div class="MCBreadcrumbsBox"><span class="MCBreadcrumbsPrefix">You are here: </span><a class="MCBreadcrumbsLink" href="../../../../basics.htm">Basics Operations & Concepts</a><span class="MCBreadcrumbsDivider"> > </span><a class="MCBreadcrumbsLink" href="../../../update_concept.htm">Update Concept</a><span class="MCBreadcrumbsDivider"> > </span><a class="MCBreadcrumbsLink" href="../../transparent_persistence.htm">Transparent Persistence</a><span class="MCBreadcrumbsDivider"> > </span><span class="MCBreadcrumbs">Object Clone</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>Object Clone</h1> <p>Platform implementations of #clone is not compatible with <span class="MCTextPopup"><a href="javascript:void(0);" class="MCTextPopupSpot" onclick="FMCTextPopup( event, this ); return false;">TP<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; ">Transparent Persistence</span></span>. </p> <p>Both java and .NET object implementations provide <code>#clone</code> method for default objects, which is enabled by implementing <code>Cloneable/ICloneable</code> interface. This implementation is a shallow clone, i.e. only the top-level object fields are duplicated, all the referenced(children) objects are only copied as references to the same object in the parent clone. But how it affects Transparent Persistence?</p> <p>If you remember <a href="../transparent_persistence_implementation.htm">Transparent Persistence Implementation</a>you must know that a special <code>Activator</code> field is used to bind an object to the object container. Consequently, the default clone will copy this <code>Activatable</code> field to the object's duplicate, which will produce ambiguity as the object container won't know which object should be activated for write.</p> <p>Let's look how it will affect db4o in practice. We will use a usual <a href="car.htm">Car</a> class and make it cloneable. Use the following code to store a car object and it's clone: </p> <p MadCap:conditions="Global.Primary:java" /> <p MadCap:conditions="Primary..NET,Primary.c#,Primary.All languages"> <pre class="prettyprint" xml:space="preserve">TPCloneExample.cs: StoreCar private static void StoreCar() { File.Delete(Db4oFileName); IObjectContainer container = Database(Db4oFactory.NewConfiguration()); if (container != null) { try { // create a car Car car = new Car("BMW", new Pilot("Rubens Barrichello")); container.Store(car); Car car1 = (Car)car.Clone(); container.Store(car1); } finally { CloseDatabase(); } } }</pre> </p> <p MadCap:conditions="Global.Primary:cs" /> <p MadCap:conditions="Primary..NET,Primary.VB.NET,Primary.All languages"> <pre class="prettyprint lang-vb" xml:space="preserve">TPCloneExample.vb: StoreCar Private Shared Sub StoreCar() File.Delete(Db4oFileName) Dim container As IObjectContainer = _ Database(Db4oFactory.NewConfiguration()) If container IsNot Nothing Then Try ' create a car Dim car As New Car("BMW", New _ Pilot("Rubens Barrichello")) container.Store(car) Dim car1 As Car = DirectCast(car.Clone(), Car) container.Store(car1) Finally CloseDatabase() End Try End If End Sub</pre> </p> <p MadCap:conditions="Global.Primary:vb" /> <p>So it works for the first store, but what if we will clone an object retrieved from the database?</p> <p MadCap:conditions="Global.Primary:java" /> <p MadCap:conditions="Primary..NET,Primary.c#,Primary.All languages"> <pre class="prettyprint" xml:space="preserve">TPCloneExample.cs: TestClone private static void TestClone() { IConfiguration configuration = ConfigureTP(); IObjectContainer container = Database(configuration); if (container != null) { try { IObjectSet result = container.QueryByExample(new Car(null, null)); ListResult(result); Car car = null; Car car1 = null; if (result.Size() > 0) { car = (Car)result[0]; System.Console.WriteLine("Retrieved car: " + car); car1 = (Car)car.Clone(); System.Console.WriteLine("Storing cloned car: " + car1); container.Store(car1); container.Commit(); } } finally { CloseDatabase(); } } }</pre> </p> <p MadCap:conditions="Global.Primary:cs" /> <p MadCap:conditions="Primary..NET,Primary.VB.NET,Primary.All languages"> <pre class="prettyprint lang-vb" xml:space="preserve">TPCloneExample.vb: TestClone Private Shared Sub TestClone() Dim configuration As IConfiguration = ConfigureTP() Dim container As IObjectContainer = Database(configuration) If container IsNot Nothing Then Try Dim result As IObjectSet = container.QueryByExample( _ New Car(Nothing, Nothing)) ListResult(result) Dim car As Car = Nothing Dim car1 As Car = Nothing If result.Size() > 0 Then car = DirectCast(result(0), Car) System.Console.WriteLine("Retrieved car: " _ + car.ToString()) car1 = DirectCast(car.Clone(), Car) System.Console.WriteLine("Storing cloned car: " _ + car1.ToString()) container.Store(car1) container.Commit() End If Finally CloseDatabase() End Try End If End Sub</pre> </p> <p MadCap:conditions="Global.Primary:vb" /> <p>The code above throws an exception when the cloned object is being bound to the object container. Luckily we can easily fix it by overriding #clone method and setting activator to null: </p> <p MadCap:conditions="Global.Primary:java" /> <p MadCap:conditions="Primary..NET,Primary.c#,Primary.All languages"> <pre class="prettyprint" xml:space="preserve">Car.cs: Clone public object Clone() { Car test = (Car)base.MemberwiseClone(); test._activator = null; return test; }</pre> </p> <p MadCap:conditions="Global.Primary:cs" /> <p MadCap:conditions="Primary..NET,Primary.VB.NET,Primary.All languages"> <pre class="prettyprint lang-vb" xml:space="preserve">Car.vb: Clone Public Function Clone() As Object Implements ICloneable.Clone Dim test As Car = DirectCast(MyBase.MemberwiseClone(), Car) test._activator = Nothing Return test End Function</pre> </p> <p MadCap:conditions="Global.Primary:vb" /> <p MadCap:conditions="Primary.Online">Download example code:</p> <p MadCap:conditions="Primary.Online"> <MadCap:conditionalText MadCap:conditions="Primary..NET,Primary.VB.NET,Primary.All languages"><a href="tpclonevb.zip">VB.NET </a> </MadCap:conditionalText> <MadCap:conditionalText MadCap:conditions="Primary..NET,Primary.c#,Primary.All languages"><a href="tpclonecs.zip">c# </a> </MadCap:conditionalText> </p> <script type="text/javascript" src="../../../../SkinSupport/MadCapBodyEnd.js"> </script> </body> </html>