1. Introduction
CSLA is a free 3-tier framework for .NET Framework 2.0, 3.0 and 3.5. CslaGen is a code generator for CSLA. About CSLA and CslaGen, refer to How to Use CslaGen to Generate CSLA Data Access Layer Code.
This project was born when I was trying to prove that it couldn't be done. Well... you know, it happens all the time. :)
It shows how to have a master/detail DataGridView
(DGV
for short) using CSLA DynamicRootList
or EditableRootListBase
(ERLB
for short) as the master list object. If you use ERLB
for the master list, auto save is a standard feature. This project also shows how to implement auto save on the detail list. As a bonus, you get both lists sorted.
This project shows a detailed example of a CslaGen project with all major issues discussed. CslaGen doesn't support DynamicRootList
generation as we speak (March 2009). Also as a bonus, you can see the changes you need to do in order to transform CslaGen object types EditableRootCollection + EditableSwitchable into proper CSLA DynamicRootList
+ DynamicRoot
.
1.1. Technical Stuff
- CslaGen doesn't have version numbers. I use a slightly customized version (including changed template files) that you can download here.
- The solution includes CSLA 3.0.5 object code under the References folder.
- The solution builds under .NET Framework 2.0 and Visual Studio 2008.
- Microsoft SQL Server 2005 was used in this project, but you can also use the Express version.
2. Background
CSLA framework has different kinds of objects and EditableRootListBase
(or DynamicRootList
) was the last one to join the framework. It was designed with the sole purpose of data binding with Windows Forms DGV
. Under CSLA, objects follow some guidelines. I will point out only the ones that are relevant for this project:
- Root objects are the only kind of objects that are loaded and saved on their own.
- Child objects are loaded and saved by their parent (be it root or another child object).
- Usually a child object doesn't have a reference to its parent (and shouldn't need it).
ERLB
is an exception to the general principle since it's a root object (root list) made of root objects.
- You can find more details on the Glossary of Common Terms.
- An
EditableRootList
is a list of objects. Those objects must be child objects. Suppose you have a list of employees as an EditableRootList
. Every employee would be an EditableChild
. Once you edit employee data (employee is a child object), in order to save it, you must save the whole employee list (the root). This isn't a practical proposition. Usually what you do is have a root read only list of all employees that allows you to choose the one you want to edit as a root object (an independent object, not a child of the root read only list). But this isn't the way DGV
works. So a new breed of objects was born:
EditableRootListBase
, a root collection of root objects
ERLB
is a root collection that loads objects but that allows you to save each one separately, i.e. each object in the collection is a root object. That matches the behavior of DGV
that saves each row as soon as you move to another row.
2.1. What's In A Name?
It took me some trouble to understand the "not so common terms" but this issue is not as trivial as you could think, since it reveals important things about ERLB
. CSLA templates now include a DynamicRootList
as well as a DynamicRoot
. As mentioned before, we know DynamicRootList
is another name for ERLB
. But what about DynamicRoot
? Why can't we use the EditableRoot
template? In fact ERLB
uses root objects, but not common editable root objects because they are loaded like an editable child is loaded. It turns out that CslaGen object type EditableSwitchable can be loaded both as an editable root and editable child. As we will see later, using CslaGen object types EditableRootCollection + EditableSwitchable is the closest thing to DynamicRootList
+ DynamicRoot
generation since it requires only small changes to get the job done.
For simplicity sake, from now on we will use only DynamicRootList
and will drop the names EditableRootListBase
and ERLB
. Likewise we will only use DynamicRoot
and will drop EditableRoot
.
3. Other Points of Interest
Most people turn to ProjectTracker for examples of CSLA use. Besides a comprehensive example of DynamicRootList
, this article offers a different source of use examples. You may find these examples interesting:
- use of
SortedBindingList
to sort the DataGridView
- use of
AddBusinessRules
with the new syntax
- use of
System.Threading.Interlocked.Decrement
to get unique temporary IDs for new objects
- optimistic concurrency and
DataPortal
events (both standard in CslaGen)
- complete CslaGen project documentation with all less obvious options discussed (refer to the Appendix for a complete collection of screen shots)
4. Use Cases
For this example project, I chose the subject "Brands & Models". Each brand is the parent of several models and no model is child of two brands. There can be no two brands with the same name. For a given brand, there can be no two models with the same name although the same model name may exist on different brands. Note that name match is case insensitive.
As I intended to make this re-usable, at the UI (User Interface) level, the names are all around "master" and "detail". At BO (Business Objects) level, I use the real object names. In order to re-use it, you just need to replace BrandColl
, Brand
, ModelColl
and Model
with your own object names. To make it even more re-usable, you should make it a Component.
5. The Database
The database Warehouse has a table for brands and another for models. BrandID
is the foreign key for models table.
Fig. 1 - Warehouse database diagram.
The Price
column is defined as money
under SQL Server. For .NET Framework the data type used is Decimal
.
CslaGen supports optimistic concurrency automatically if you include a SQL column of timestamp
data type. In spite of its name, this data type isn't time related at all but is really a version count starting at zero and increasing whenever there is a row update. That's why I prefer to call it RowVersion
. Optimistic concurrency checks if the present row version matches the row version at the time the object was fetched and if it doesn't, it refuses to save, warning you that the object has changed. This means some other user has changed or deleted it.
Under SQL Server run the scripts to create the database and the tables. While you are at it, also run the scripts to create the stored procedures. The project file CslaERLB1.zip includes all the scripts. You will populate the database yourself using the compiled sources.
6. The Objects
Although CslaGen doesn't support DynamicRootList
(yet), a CslaGen file (Warehouse.xml) is included in CslaERLB1.zip. I used the CslaGen object types EditableRootCollection and EditableSwitchable. Then I made some changes to the generated files and transform the set into a proper set of DynamicRootList
+ DynamicRoot
objects (CSLA template naming).
Fig. 2 - Warehouse object diagram (only non generated objects are visible).
BrandColl
is a root collection of Brand
objects. It's a DynamicRootList
, a collection made of DynamicRoot
objects. So Brand
is also a root object. Brand
object is the parent of ModelColl
collection and ModelColl
is a collection of Model
objects.
NOTES
- The Nested Types are the criteria for the object.
- The
static
field _lastID
is used as a seed for temporary ID, before new objects are committed to the database and acquire the real ID (as supplied by the database).
- The
AddBusinessRules
method is responsible for adding the validation rules to the object. CslaGen has some support for validation rules. But I really prefer to do it myself. In this case, it uses the new syntax (since CSLA 2.1).
- The
NoDuplicates
method is a validation rule that checks the name doesn't exist in the collection according to the rules explained in 4. Use cases.
- In order to use
DGV
, each collection must have an AddNewCore
method.
Other Parts of this Article
History
- Document version 1: 12 March 2009
- Code version 1.1: 14 March 2009 - bug correction