I have to admit that I wasn’t expecting this kind of success, but it appears that the Tips & Tricks post was hugely popular with many readers. That’s why once again today I’m writing to answer a question I get asked a lot, and one that many of you voted for: is there a practical example of a document lock?
When you need to implement the lock on entities in an application, you have to start with a few simple questions, because the answers will give us the rules we need to implement the service:
- where do I save the locks?
- how do I identify the locks and the locked entities?
- how long before a lock is considered obsolete?
The first question masks an implicit idea: there is no standard way to store application locks. We can save them to XML files, we can store them as a new field in each table of each entity, we can keep them temporarily in memory in a server session. The route I prefer is adding a locks table to the database.
The second question derives directly from my answer to the first: if I only use one table, how can I recognize a lock on an Invoice from a lock on a Client? In this case, we get help from the Document Orientation getDNA function, which returns a unique identifier of the entity throughout the application. It doesn’t matter whether I use the DocID or the normal counters, a DNA is always unique (within the same database). So, to correctly identify the locks of all entities in my application, I just need to have a Locks table with the fields ID, DocDNA, User, and Date Time to indicate who has taken a lock on which entity and when.
The third question always arises during implementation. The idea behind the lock service is this: when the user starts changing an entity, the system tries to get a lock. If it can do so, it writes it to the database; if it can’t, it cancels the change and alerts the user. When the user stops working on the entity, the lock is released. But what happens if a lock is in place and then the application crashes, the server is rebooted, or there is an error? The lock won’t be released, and that entity will be locked forever. That’s why you always have to make sure that locks will be considered obsolete, and therefore null, after a day.
Once we’ve answered these questions we can get started with implementation. Like many Document Orientation services, the document lock is based on use of a Document Helper, the class that allows us to globalize the behavior of the application classes. In this example project I have implemented the lock using the getLock and releaseLock events.
In the getLock, I check whether the entity the user modified is locked by another operator searching for it by DNA and then, depending on the result, I react differently to set the value of the Result input/output parameter:
- if I can’t find it, I insert the row in the database, saving the time and current user, and I set result to true;
- if I can find it and the user locking it is the current user, I refresh the lock, updating the time, and set result to true;
- if I can find it and the user locking it is not the current user but the lock is obsolete (more than a day old), I release the lock, insert a new one and set result to true;
- if I can find it and the user locking it is not the current user and the lock is not obsolete, I set result to false and display a message to the user.
Try it and see: launch the example project and log in two times from two different browsers using two different usernames. Change a row in the first browser and leave the panel in updated status. Then go to the second and try to edit the same row. You won’t be able to edit the entity from this second window, and you’ll see an error on screen.
Don’t say I never did anything for you.