<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <link rel="stylesheet" type="text/css" href="docs.css"> <!--[if gte IE 5]> <link href="docs_ie.css" rel="stylesheet" type="text/css"> <![endif]--> </head> <body><div id="pagecontainer"><table><tr><td width="5"> </td><td><a name="ClientServer"></a><br> <a name="outline212"></a><br><h1>12. Client/Server</h1><br> Now that we have seen how transactions work in db4o conceptually, we are prepared to tackle concurrently executing transactions.<br> <br> We start by preparing our database in the familiar way.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// setFirstCar<br> Pilot pilot = new Pilot("Rubens Barrichello", 99);<br> Car car = new Car("BMW");<br> car.Pilot = pilot;<br> db.Store(car);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter6.ClientServerExample", "setFirstCar")' /></td></tr></table> <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// setSecondCar<br> Pilot pilot = new Pilot("Michael Schumacher", 100);<br> Car car = new Car("Ferrari");<br> car.Pilot = pilot;<br> db.Store(car);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter6.ClientServerExample", "setSecondCar")' /></td></tr></table> <br> <br> <ul> <a name="outline213"></a><br><h2>12.1. Embedded server</h2><br> From the API side, there's no real difference between transactions executing concurrently within the same runtime and transactions executed against a remote server. To use concurrent transactions within a single runtime , we just open a db4o server on our database file, directing it to run on port 0, thereby declaring that no networking will take place.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// accessLocalServer<br> using(IObjectServer server = Db4oClientServer.OpenServer(YapFileName, 0))<br> {<br> using(IObjectContainer client = server.OpenClient())<br> {<br> // Do something with this client, or open more clients<br> }<br> }</code></td></tr></table> <br> <br> Again, we will delegate opening and closing the server to our environment to focus on client interactions.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// queryLocalServer<br> using(IObjectContainer client = server.OpenClient())<br> {<br> ListResult(client.QueryByExample(new Car(null)));<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter6.ClientServerExample", "queryLocalServer")' /></td></tr></table> <br> <br> The transaction level in db4o is <em>read committed</em> . However, each client container maintains its own weak reference cache of already known objects. To make all changes committed by other clients immediately, we have to explicitly refresh known objects from the server. We will delegate this task to a specialized version of our #ListResult() method.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>public static void ListRefreshedResult(IObjectContainer container, IObjectSet items, int depth)<br> {<br> Console.WriteLine(items.Count);<br> foreach (object item in items)<br> { <br> container.Ext().Refresh(item, depth);<br> Console.WriteLine(item);<br> }<br> }</code></td></tr></table> <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// demonstrateLocalReadCommitted<br> using(IObjectContainer client1 =server.OpenClient(),<br> client2 =server.OpenClient())<br> {<br> Pilot pilot = new Pilot("David Coulthard", 98);<br> IObjectSet result = client1.QueryByExample(new Car("BMW"));<br> Car car = (Car)result.Next();<br> car.Pilot = pilot;<br> client1.Store(car);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> client1.Commit();<br> ListResult(client1.QueryByExample(typeof(Car))); <br> ListRefreshedResult(client2, client2.QueryByExample(typeof(Car)), 2);<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter6.ClientServerExample", "demonstrateLocalReadCommitted")' /></td></tr></table> <br> <br> Simple rollbacks just work as you might expect now.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// demonstrateLocalRollback<br> using (IObjectContainer client1 = server.OpenClient(),<br> client2 = server.OpenClient())<br> {<br> IObjectSet result = client1.QueryByExample(new Car("BMW"));<br> Car car = (Car) result.Next();<br> car.Pilot = new Pilot("Someone else", 0);<br> client1.Store(car);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> client1.Rollback();<br> client1.Ext().Refresh(car, 2);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter6.ClientServerExample", "demonstrateLocalRollback")' /></td></tr></table> <br> <br> <a name="outline214"></a><br><h2>12.2. Networking</h2><br> From here it's only a small step towards operating db4o over a TCP/IP network. We just specify a port number greater than zero and set up one or more accounts for our client(s).<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// accessRemoteServer<br> using(IObjectServer server = Db4oClientServer.OpenServer(YapFileName, ServerPort))<br> {<br> server.GrantAccess(ServerUser, ServerPassword);<br> using(IObjectContainer client = Db4oClientServer.OpenClient("localhost", ServerPort, ServerUser, ServerPassword))<br> {<br> // Do something with this client, or open more clients<br> }<br> }</code></td></tr></table> <br> <br> The client connects providing host, port, user name and password.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// queryRemoteServer<br> using(IObjectContainer client = Db4oClientServer.OpenClient("localhost", port, user, password))<br> {<br> ListResult(client.QueryByExample(new Car(null)));<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter6.ClientServerExample", "queryRemoteServer")' /></td></tr></table> <br> <br> Everything else is absolutely identical to the local server examples above.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// demonstrateRemoteReadCommitted<br> using(IObjectContainer client1 = Db4oClientServer.OpenClient("localhost", port, user, password),<br> client2 = Db4oClientServer.OpenClient("localhost", port, user, password))<br> {<br> Pilot pilot = new Pilot("Jenson Button", 97);<br> IObjectSet result = client1.QueryByExample(new Car(null));<br> Car car = (Car)result.Next();<br> car.Pilot = pilot;<br> client1.Store(car);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> client1.Commit();<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter6.ClientServerExample", "demonstrateRemoteReadCommitted")' /></td></tr></table> <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// demonstrateRemoteRollback<br> using(IObjectContainer client1 =Db4oClientServer.OpenClient("localhost", port, user, password),<br> client2 =Db4oClientServer.OpenClient("localhost", port, user, password))<br> {<br> IObjectSet result = client1.QueryByExample(new Car(null));<br> Car car = (Car) result.Next();<br> car.Pilot = new Pilot("Someone else", 0);<br> client1.Store(car);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> client1.Rollback();<br> client1.Ext().Refresh(car, 2);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter6.ClientServerExample", "demonstrateRemoteRollback")' /></td></tr></table> <br> <br> <br> <br> <a name="outline215"></a><br><h2>12.3. Out-of-band signalling</h2><br> Sometimes a client needs to send a special message to a server in order to tell the server to do something. The server may need to be signalled to perform a defragment or it may need to be signalled to shut itself down gracefully.<br> <br> This is configured bysetting MessageRecipient parameter to the object that will process client-initiated messages.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>public void RunServer()<br> {<br> lock(this)<br> {<br> IServerConfiguration config = Db4oClientServer.NewServerConfiguration();<br> // Using the messaging functionality to redirect all<br> // messages to this.processMessage<br> config.Networking.MessageRecipient = this;<br> IObjectServer db4oServer = Db4oClientServer.OpenServer(config, FILE, PORT);<br> db4oServer.GrantAccess(USER, PASS);<br> <br> try<br> {<br> if (! stop)<br> {<br> // wait forever until Close will change stop variable<br> Monitor.Wait(this);<br> }<br> }<br> catch (Exception e)<br> {<br> Console.WriteLine(e.ToString());<br> }<br> db4oServer.Close();<br> }<br> }</code></td></tr></table> <br> <br> The message is received and processed by a #ProcessMessage() method:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>public void ProcessMessage(IMessageContext con, object message)<br> {<br> if (message is StopServer)<br> {<br> Close();<br> }<br> }</code></td></tr></table> <br> <br> Db4o allows a client to send an arbitrary signal or message to a server by sending a plain object to the server. The server will receive a callback message, including the object that came from the client. The server can interpret this message however it wants.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>public static void Main(string[] args)<br> {<br> IObjectContainer IObjectContainer = null;<br> try<br> {<br> // connect to the server<br> IObjectContainer = Db4oClientServer.OpenClient(Db4oClientServer.NewClientConfiguration(),<br> HOST, PORT, USER, PASS);<br> }<br> catch (Exception e)<br> {<br> Console.WriteLine(e.ToString());<br> }<br> <br> if (IObjectContainer != null)<br> {<br> // get the messageSender for the IObjectContainer<br> IMessageSender messageSender = IObjectContainer.Ext()<br> .Configure().ClientServer().GetMessageSender();<br> // send an instance of a StopServer object<br> messageSender.Send(new StopServer());<br> <br> // close the IObjectContainer<br> IObjectContainer.Close();<br> }<br> }</code></td></tr></table> <br> <br> <a name="outline216"></a><br><h2>12.4. Putting it all together: a simple but complete db4o server</h2><br> Let's put all of this information together now to implement a simple standalone db4o server with a special client that can tell the server to shut itself down gracefully on demand.<br> <br> First, both the client and the server need some shared configuration information. We will provide this using an interface:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>namespace Db4odoc.Tutorial.F1.Chapter6<br> {<br> /// <summary><br> /// Configuration used for StartServer and StopServer.<br> /// </summary><br> public class ServerInfo<br> {<br> /// <summary><br> /// the host to be used.<br> /// If you want to run the client server examples on two computers,<br> /// enter the computer name of the one that you want to use as server. <br> /// </summary><br> public const string HOST = "localhost"; <br> /// <summary><br> /// the database file to be used by the server.<br> /// </summary><br> public const string FILE = "formula1.yap";<br> /// <summary><br> /// the port to be used by the server.<br> /// </summary><br> public const int PORT = 4488;<br> /// <summary><br> /// the user name for access control.<br> /// </summary><br> public const string USER = "db4o";<br> <br> /// <summary><br> /// the pasword for access control.<br> /// </summary><br> public const string PASS = "db4o";<br> }<br> }<br> </code></td></tr></table> <br> <br> Now we'll create the server:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using System.Threading;<br> using Db4objects.Db4o;<br> using Db4objects.Db4o.CS;<br> using Db4objects.Db4o.CS.Config;<br> using Db4objects.Db4o.Messaging;<br> namespace Db4odoc.Tutorial.F1.Chapter6<br> {<br> /// <summary><br> /// starts a db4o server with the settings from ServerInfo.<br> /// This is a typical setup for a long running server.<br> /// The Server may be stopped from a remote location by running<br> /// StopServer. The StartServer instance is used as a MessageRecipient<br> /// and reacts to receiving an instance of a StopServer object.<br> /// Note that all user classes need to be present on the server side<br> /// and that all possible Db4oFactory.Configure() calls to alter the db4o<br> /// configuration need to be executed on the client and on the server.<br> /// </summary><br> public class StartServer : ServerInfo, IMessageRecipient<br> {<br> /// <summary><br> /// setting the value to true denotes that the server should be closed<br> /// </summary><br> private bool stop = false;<br> /// <summary><br> /// starts a db4o server using the configuration from<br> /// ServerInfo.<br> /// </summary><br> public static void Main(string[] arguments)<br> {<br> new StartServer().RunServer();<br> }<br> /// <summary><br> /// opens the IObjectServer, and waits forever until Close() is called<br> /// or a StopServer message is being received.<br> /// </summary><br> public void RunServer()<br> {<br> lock(this)<br> {<br> IServerConfiguration config = Db4oClientServer.NewServerConfiguration();<br> // Using the messaging functionality to redirect all<br> // messages to this.processMessage<br> config.Networking.MessageRecipient = this;<br> IObjectServer db4oServer = Db4oClientServer.OpenServer(config, FILE, PORT);<br> db4oServer.GrantAccess(USER, PASS);<br> <br> try<br> {<br> if (! stop)<br> {<br> // wait forever until Close will change stop variable<br> Monitor.Wait(this);<br> }<br> }<br> catch (Exception e)<br> {<br> Console.WriteLine(e.ToString());<br> }<br> db4oServer.Close();<br> }<br> }<br> /// <summary><br> /// messaging callback<br> /// see com.db4o.messaging.MessageRecipient#ProcessMessage()<br> /// </summary><br> public void ProcessMessage(IMessageContext con, object message)<br> {<br> if (message is StopServer)<br> {<br> Close();<br> }<br> }<br> /// <summary><br> /// closes this server.<br> /// </summary><br> public void Close()<br> {<br> lock(this)<br> {<br> stop = true;<br> Monitor.PulseAll(this);<br> }<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> And last but not least, the client that stops the server.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using Db4objects.Db4o;<br> using Db4objects.Db4o.CS;<br> using Db4objects.Db4o.Messaging;<br> namespace Db4odoc.Tutorial.F1.Chapter6<br> {<br> /// <summary><br> /// stops the db4o Server started with StartServer.<br> /// This is done by opening a client connection<br> /// to the server and by sending a StopServer object as<br> /// a message. StartServer will react in it's<br> /// processMessage method.<br> /// </summary><br> public class StopServer : ServerInfo<br> {<br> /// <summary><br> /// stops a db4o Server started with StartServer.<br> /// </summary><br> /// <exception cref="Exception" /><br> public static void Main(string[] args)<br> {<br> IObjectContainer IObjectContainer = null;<br> try<br> {<br> // connect to the server<br> IObjectContainer = Db4oClientServer.OpenClient(Db4oClientServer.NewClientConfiguration(),<br> HOST, PORT, USER, PASS);<br> }<br> catch (Exception e)<br> {<br> Console.WriteLine(e.ToString());<br> }<br> <br> if (IObjectContainer != null)<br> {<br> // get the messageSender for the IObjectContainer<br> IMessageSender messageSender = IObjectContainer.Ext()<br> .Configure().ClientServer().GetMessageSender();<br> // send an instance of a StopServer object<br> messageSender.Send(new StopServer());<br> <br> // close the IObjectContainer<br> IObjectContainer.Close();<br> }<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> <a name="outline217"></a><br><h2>12.5. Conclusion</h2><br> That's it, folks. No, of course it isn't. There's much more to db4o we haven't covered yet: schema evolution, custom persistence for your classes, writing your own query objects, etc. A much more thorough documentation is provided in the reference that you should have also received with the download or <a href="http://developer.db4o.com/Documentation.aspx" target="_blank">online</a>.<br> <br> We hope that this tutorial has helped to get you started with db4o. How should you continue now?<br> <br> - Register on db4o developer <a href="http://www.db4o.com/Users/register.aspx" target="_blank">website</a>. <br> <br> - You could browse the remaining chapters. They are a selection of themes from the reference that very frequently come up as questions in our <a href="http://developer.db4o.com/Forums.aspx" target="_blank">http://developer.db4o.com/Forums.aspx</a>.<br> <br> -<em>(Interactive version only)</em>While this tutorial is basically sequential in nature, try to switch back and forth between the chapters and execute the sample snippets in arbitrary order. You will be working with the same database throughout; sometimes you may just get stuck or even induce exceptions, but you can always reset the database via the console window.<br> <br> - The examples we've worked through are included in your db4o distribution in full source code. Feel free to experiment with it.<br> <br> - If you're stuck, browse the information on our <a href="http://www.db4o.com/" target="_blank">web site</a>, check if your problem is submitted to <a href="http://tracker.db4o.com/" target="_blank">Jira</a> or visit our forums at <a href="http://developer.db4o.com/Forums.aspx" target="_blank">http://developer.db4o.com/Forums.aspx</a>.<br> <br> <br> <a name="outline218"></a><br><h2>12.6. Full source</h2><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using System.IO;<br> using Db4objects.Db4o;<br> using Db4objects.Db4o.CS;<br> using Db4objects.Db4o.CS.Config;<br> namespace Db4odoc.Tutorial.F1.Chapter6<br> {<br> public class ClientServerExample : Util<br> {<br> readonly static string YapFileName = Path.Combine(<br> Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),<br> "formula1.yap");<br> readonly static int ServerPort = 0xdb40;<br> readonly static string ServerUser = "user";<br> readonly static string ServerPassword = "password";<br> public static void Main(string[] args)<br> {<br> File.Delete(YapFileName);<br> AccessLocalServer();<br> File.Delete(YapFileName);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))<br> {<br> SetFirstCar(db);<br> SetSecondCar(db);<br> }<br> IServerConfiguration config = Db4oClientServer.NewServerConfiguration();<br> config.Common.ObjectClass(typeof(Car)).UpdateDepth(3);<br> using(IObjectServer server = Db4oClientServer.OpenServer(config,<br> YapFileName, 0))<br> {<br> QueryLocalServer(server);<br> DemonstrateLocalReadCommitted(server);<br> DemonstrateLocalRollback(server);<br> }<br> <br> AccessRemoteServer();<br> using(IObjectServer server = Db4oClientServer.OpenServer(Db4oClientServer.NewServerConfiguration(),<br> YapFileName, ServerPort))<br> {<br> server.GrantAccess(ServerUser, ServerPassword);<br> QueryRemoteServer(ServerPort, ServerUser, ServerPassword);<br> DemonstrateRemoteReadCommitted(ServerPort, ServerUser, ServerPassword);<br> DemonstrateRemoteRollback(ServerPort, ServerUser, ServerPassword);<br> }<br> }<br> <br> public static void SetFirstCar(IObjectContainer db)<br> {<br> Pilot pilot = new Pilot("Rubens Barrichello", 99);<br> Car car = new Car("BMW");<br> car.Pilot = pilot;<br> db.Store(car);<br> }<br> <br> public static void SetSecondCar(IObjectContainer db)<br> {<br> Pilot pilot = new Pilot("Michael Schumacher", 100);<br> Car car = new Car("Ferrari");<br> car.Pilot = pilot;<br> db.Store(car);<br> }<br> <br> public static void AccessLocalServer()<br> {<br> using(IObjectServer server = Db4oClientServer.OpenServer(YapFileName, 0))<br> {<br> using(IObjectContainer client = server.OpenClient())<br> {<br> // Do something with this client, or open more clients<br> }<br> }<br> }<br> <br> public static void QueryLocalServer(IObjectServer server)<br> {<br> using(IObjectContainer client = server.OpenClient())<br> {<br> ListResult(client.QueryByExample(new Car(null)));<br> }<br> }<br> <br> <br> public static void DemonstrateLocalReadCommitted(IObjectServer server)<br> {<br> using(IObjectContainer client1 =server.OpenClient(),<br> client2 =server.OpenClient())<br> {<br> Pilot pilot = new Pilot("David Coulthard", 98);<br> IObjectSet result = client1.QueryByExample(new Car("BMW"));<br> Car car = (Car)result.Next();<br> car.Pilot = pilot;<br> client1.Store(car);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> client1.Commit();<br> ListResult(client1.QueryByExample(typeof(Car))); <br> ListRefreshedResult(client2, client2.QueryByExample(typeof(Car)), 2);<br> }<br> }<br> <br> public static void DemonstrateLocalRollback(IObjectServer server)<br> {<br> using (IObjectContainer client1 = server.OpenClient(),<br> client2 = server.OpenClient())<br> {<br> IObjectSet result = client1.QueryByExample(new Car("BMW"));<br> Car car = (Car) result.Next();<br> car.Pilot = new Pilot("Someone else", 0);<br> client1.Store(car);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> client1.Rollback();<br> client1.Ext().Refresh(car, 2);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> }<br> }<br> <br> public static void AccessRemoteServer()<br> {<br> using(IObjectServer server = Db4oClientServer.OpenServer(YapFileName, ServerPort))<br> {<br> server.GrantAccess(ServerUser, ServerPassword);<br> using(IObjectContainer client = Db4oClientServer.OpenClient("localhost", ServerPort, ServerUser, ServerPassword))<br> {<br> // Do something with this client, or open more clients<br> }<br> }<br> }<br> <br> public static void QueryRemoteServer(int port, string user, string password)<br> {<br> using(IObjectContainer client = Db4oClientServer.OpenClient("localhost", port, user, password))<br> {<br> ListResult(client.QueryByExample(new Car(null)));<br> }<br> }<br> <br> public static void DemonstrateRemoteReadCommitted(int port, string user, string password)<br> {<br> using(IObjectContainer client1 = Db4oClientServer.OpenClient("localhost", port, user, password),<br> client2 = Db4oClientServer.OpenClient("localhost", port, user, password))<br> {<br> Pilot pilot = new Pilot("Jenson Button", 97);<br> IObjectSet result = client1.QueryByExample(new Car(null));<br> Car car = (Car)result.Next();<br> car.Pilot = pilot;<br> client1.Store(car);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> client1.Commit();<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> }<br> }<br> <br> public static void DemonstrateRemoteRollback(int port, string user, string password)<br> {<br> using(IObjectContainer client1 =Db4oClientServer.OpenClient("localhost", port, user, password),<br> client2 =Db4oClientServer.OpenClient("localhost", port, user, password))<br> {<br> IObjectSet result = client1.QueryByExample(new Car(null));<br> Car car = (Car) result.Next();<br> car.Pilot = new Pilot("Someone else", 0);<br> client1.Store(car);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> client1.Rollback();<br> client1.Ext().Refresh(car, 2);<br> ListResult(client1.QueryByExample(new Car(null)));<br> ListResult(client2.QueryByExample(new Car(null)));<br> }<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br><br><div id="footer"><p align="center">Do you have any questions, suggestions or feedback? Ask your questions in the <a href="http://developer.db4o.com/Forums.aspx" target=_top>db4o forums</a>. Join the <a href="http://developer.db4o.com" target=_top>db4o community</a> for addional resources and news.<br><br><a href="http://www.db4o.com/" target=_top><small>www.db4o.com</small></a></p>.</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></td></tr></table></div></body></html>