Concepts - Stateless persistence

Preface

A remark on stateless development is in order, because a lot of developers misunderstand what 'state' really means in the n-tier context. By convention, all n-tier applications should be 'stateless'. This means that the total application is not in some kind of 'state' by holding information in memory, or better: the separate tiers shouldn't be in a certain 'state' where they hold information in memory. The 'state' of the application is held by the database(s) used. This model is completely the opposite of the stateful way the so called 'fat'-clients used to work: the user worked with the complete application on his machine, and the application's state was held in memory.

The reason for a stateless approach is quite simple: multi-user. In a fat client, single user system, the application state was the same as the user's state, and thus it was a great performance gain to keep that user-state in memory instead of the database. For a set of black-boxes stacked on top of each other, serving more than one user, the application state is not the same as the user's state, in fact, for every user, the application can act completely different. In these circumstances, in the n-tier application world, a stateless approach is more convenient, since the logic can assume correctly what the current state of the application is (which is stored in the database) and can use other system parts, like COM+ and MTS or even webservices, without having to negotiate a current 'state'. Also, the reuse of system resources is very flexible in a stateless environment: as soon as a given object is done using another object, it is destroyed (normal objects) or returned to a pool (for example connection objects), and not held in some global store. When thousands of users are using the system, it still will perform well, because it doesn't keep thousands of objects in a global object store but shares a smaller group of objects among the ones who need them.
Stateless development and O/R Mapping
If you work with objects that hold the data of an entity, the term 'stateless' becomes a little blurred and you can't really talk about a pure stateless environment anymore: holding any entity in memory practically makes the application stateful. Still, LLBLGen Pro will not cache the in-memory objects, and therefore considers the objects in memory as temporary mirrors of the entities in the persistent storage. Every action on entities in memory has to be considered as 'stateless actions', and should be persisted a.s.a.p. As a user of the generated code, you should not cache loaded objects in memory longer than necessary, because changes made by other threads, on other machines, to the entities in the persistent storage are not seen by your thread and therefore your code can wrongly assume the entity data held by the cached object is valid, however it is out-of-sync with the real entity in the persistent storage.

In the generated code you will find entity collection classes. These collection classes have methods to work with more than one entity and work directly on the persistent storage (using Adapter, you'll find these methods in the DataAccessAdapter class). This means that when you update a set of entities through a method on an entity collection object, you are actually modifying the real entity data, which is seen by all other threads and users in your application. This way you can be sure the changes are propagated to other threads in your application as well. For individual entities and objects holding their data: create the object, read the entity data into the object, use the data, and get rid of the entity object right after that. LLBLGen Pro doesn't use database locks on table rows to prevent some sort of concurrency control; every entity object is disconnected and can move around in the application freely. The application should be aware of the fact that when data is altered in an entity object, it has to propagate those changes a.s.a.p. back to the database.

There is no need for panic though. In most applications there will be no problem at all, and most concurrency control problems which are related to the in-memory caching problem, can be circumvented by a variety of solutions: be it optimistic concurrency control, functional locking (locking of functionality for other users if a single user is using a harmful piece of functionality) etc.
User state
User state is a confusing term, because in a way, it is a form of stateful programming. User state is the state of the application for a typical user, but only in such a way that the user thinks the application is in his state, most of the time meaning just GUI related data is kept in a stateful global store, typically in session related objects, which are common in the ASP and ASP.NET world. ASP developers know as a rule of thumb not to keep large objects in the 'session' object, like recordsets or open database connections. The reason for this is that the application suddenly becomes stateful even if the developer didn't intend this. In the .NET world, this hasn't changed. User state, for example the information a user has provided on page one and two on a four page wizard, is light and influences only the GUI tiers. Data meant for other tiers shouldn't be kept in the user state but should be stored in the database. As a rule of thumb use this: "if tier N (N being not the GUI layer) is changed into a stateless webservice, placed on a webserver on the internet, thus not in your local secure network, will the application still work as planned or do you have to change a lot in the application to keep it together?" When you have to change a lot, your application isn't stateless, when you don't have to change a lot, your application is pretty 'stateless' and you're well on track!

LLBLGen Pro v3.1 documentation. ©2011 Solutions Design