Search code examples
db4o

prevent same object return in the same time in db4o


i am using db4o in a asp.net web application, as you know when db4o returns a list of objects they are not ordered.

in my website, i run a query and get the last object in the results and work on it (some processing and then update one of its fields).

my question is, if when i am working on that object , if another user arrive and run that query again , the same object returns to him, and both of users get same object.

i don't want to allow this to happen. how can i prevent it from happening ?


Solution

  • Not sure if DB4O provides anything like this out of the box, but could implement some kind of pessimistic lock yourself, whereby the same object either won't be returned or will be returned in a read-only mode. You'd need to maintain a list of objects being edited, and check this list each time you return your objects. But then there are problems such as users leaving and object getting stuck in 'edit mode' etc. You generally need some kind of service involving a timeout mechanism to deal with that. It can get complicated.

    Or do it optimistically, e.g. let both users edit it but only save changes from the first user, and give the second user a warning when they try to save it. Usually done with a timestamp.

    Edit

    To provide a concrete example, this C# code provides a basic way to 'lock' an object so it isn't brought back every time. In real life it will be more complex though.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ListTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                DataAccess dataAccess = new DataAccess();
    
                // get objects from database
                List<MyThing> things = dataAccess.GetThings();
                MyThing thingToWorkOn = things[things.Count-1];
                printThingList(things);
    
                // lock the object to work on
                dataAccess.LockThing(thingToWorkOn);
    
                // someone else gets the list - doesn't include thing being edited
                List<MyThing> moreThings = dataAccess.GetThings();
                printThingList(moreThings);
    
                // edit the object
                thingToWorkOn.Name = "Harrold";
                thingToWorkOn.Name = "Harry";
    
                // save the object and unlock it
                dataAccess.Save(thingToWorkOn);
                dataAccess.UnlockThing(thingToWorkOn);
    
                // now when someone else gets the list, includes all objects
                List<MyThing> evenMoreThings = dataAccess.GetThings();
                printThingList(evenMoreThings);
            }
    
            static void printThingList(List<MyThing> things)
            {
                Console.WriteLine("* Things *");
                things.ForEach(x => Console.WriteLine(x.Name));
                Console.WriteLine();
            }
        }
    
        // The objects you're working with.  Could just use 'object' or some interface.
        class MyThing : IEquatable<MyThing>
        {
            public string Name { get; set; }
    
            public bool Equals(MyThing other)
            {
                return other.Name == this.Name;
            }
        }
    
        // Class to get objects from database.
        class DataAccess
        {
            // simple list to store 'locked' objects
            private static List<MyThing> lockedThings = new List<MyThing>();
    
            // Get all objects except the locked ones
            public List<MyThing> GetThings()
            {
                List<MyThing> thingsFromDatabase = LoadThingsFromDatabase();
    
                var nonLockedThings = (from thing in thingsFromDatabase
                                       where !lockedThings.Contains(thing)
                                       select thing
                                        ).ToList<MyThing>();
    
                return nonLockedThings;
            }
    
            // lock an object so it can't be seen by anyone else
            public void LockThing(MyThing thingToLock)
            {
                lockedThings.Add(thingToLock);
            }
    
            // unlock an object
            public void UnlockThing(MyThing thingToLock)
            {
                lockedThings.Remove(thingToLock);
            }
    
            public void Save(MyThing thing)
            {
                // save to database
            }
    
            // dummy method to give us some objects
            private List<MyThing> LoadThingsFromDatabase()
            {
                return new List<MyThing>() {
                    new MyThing(){ Name="Tom" },
                    new MyThing(){ Name="Dick" },
                    new MyThing(){ Name="Harry" }
                };
            }
        }
    }