Archive for category CSLA.NET
In a post from a long time ago, Eric Gunnerson asks about persisting complex objects. I’m working on a project that is using the CSLA.NET framework. One of the early decisions we made was how to get data updates back to the database. We chose to use Eric’s preferred method, which is change tracking. Eric also likes using serialization. That’s built into CSLA.NET (as well as .NET, of course), so we didn’t have to make a deliberate decision to use serialization.
One decision to make with persisting the objects is the actual mechanism for the updates. We ruled out using a dataset because we wanted to avoid the extra overhead that comes with a dataset. The examples from Rocky’s book all use stored procedures. The stored procedures have to have a parameter for every field. This means you are passing every field to the database, even when they did not change. Another option is dynamic SQL.
I had done some research in the past on the debate over stored procedures vs. dynamic SQL. One of the key issues in the debate is controlling access to the database. In some environments, dynamic SQL might mean that you have to give users access to all tables, and that might not be desirable. With an internal business application, the security can be handled through account impersonation in Enterprise Services or ASP.NET. Only one account needs to be given access to the database. In our environment, dynamic SQL seemed like a viable choice.
When profiling updates with “old-fashioned” ADO Recordsets, I observed that the recordsets generate dynamic SQL. The SQL was bloated, but reliable, and worked well with the optimistic concurrency model. I wanted to use this model, but in a more efficient manner.
In its simplest form, here is the format of a SQL statement that updates a record and also provides optimistic concurrency protection:
Set Field1 = NewValue
Where PrimaryKey = KeyValue And Field1 = OriginalValue
With our decision to use dynamic SQL inside the business object, the business object will already have most of the information needed to generate this statement. It has to know what table(s) are used to load the data. It has to know what columns are used to load the data, including the primary key value. It has to know the current value to update the database. The only optional piece is the original value. The original value is usually overwritten when the user makes changes.
One option to manage this is to double the number of variables. For each m_Field1, you would also have an m_orig_Field1, for example. This technique forces the business object developer to write two lines of code when setting each field value.
Since the update statement could be manufactured mechanically with all the necessary information, we felt there should be a way to encapsulate the necessary information. We have created “smart data” classes for the basic data types (string, integer, double, date, and boolean). Each smart data type knows the column name it is associated with, the original database value, and the current value. It turns out this is enough for efficient updates.
These smart data objects share a common interface. The interface defines three read-only properties: Column name, original value, and current value. A DataUpdater object uses this interface to generate the update statement.
Within the business object, the following lines of code are used to update a sample business object:
Dim updater As New DataUpdater(“MyTable”, m_KeyValue)
Within the updater, the SQL statement is generated and run against the database. As an added bonus, the smart data objects which have a concept of an “empty” value (i.e. string and date) also handle translating the empty value into a null value for the database.
The smart data objects are also easy to use when fetching the data. Before the smart data objects, fetch code looked like “m_Field1 = dr.GetString(“Field1”). dr refers to a SafeDataReader, which is part of the CSLA.NET framework. With smart data, the line is written as m_Field1 = New SmartString(dr, “Field1”).
The smart data object handles all the details of retrieving the value from the data reader and setting the original and current values.
We’ve added other capabilities to the smart data objects that help our Windows Forms classes, too. But that is outside of the persistence topic. These smart data objects are working very well for us. They do create more overhead, but nothing like a dataset. If you have a similar environment, perhaps you can benefit from this concept as well.
Note to self: Check out thie code in this forum message regarding an automated way to generate databinding.
An interesting discussion is going on in the CSLA.NET forum. In message 5 of the discussion, Tom Leylan points out that the discussion is getting bogged down in semantics. I would agree with Tom’s assessment. I was going to post a response of my own to his original entry. However, I realized halfway through my response that there could be multiple interpretations of the term “parent”. I canceled my response and elected to seehow others interpreted it.
I think semantics is the root cause for a significant percentage of software bugs. I also believe that these kinds of bugs are harder to detect. The main problem is that human language is very inexact. Programming languages are the exact opposite. We try to build computer programs by translating the inexactness of human language into the exactness of a programming language. Translations of this type are very, very, difficult, even for the most powerful computers on earth — our brains.
Conversely, translating from one exact language to another exact language is very easy. There are hundreds of programs to translate code from one programming language to another. In a sense, every compiler is simply a translator, since a compiler is translating a higher-level language to a lower-level language. Compilers are introduced at the undergraduate level, so they can’t be considered a terribly difficult concept. :-)
An assembler is translating assembly language to machine language. In the .NET environment, two translations are taking place. There is a compiler that translates VB, C#, J#, etc. into IL. A second compiler translates the IL into machine language.
The task is not so easy when one wants to translate English to Spanish. In fact, it’s not so easy translating from relatively similar languages. Many American jokes don’t translate very well when told in the UK, even though both countries use English as their primary language. Try using Babelfish to translate this page into French.
If you are interested in how the best and brightest are dealing with this issue, check out the Proteus project.
Last night, I installed a test project called ActiveTracker. You’ll have to have an account to the MSN group to access the link. ActiveTracker is a modification by Petar Kozul to Rocky’s ProjectTracker. ProjectTracker demonstrates many of the features of the CSLA.NET framework. ActiveTracker includes an implementation of the Observer design pattern.
It was late by the time I successfully built the solution, so I was only able to play around with the general functionality for a few minutes.
One of the Oberver features is implemented in the ProjectList dialog. The dialog lists the projects. If a project is added, the list automatically refreshes and shows the new project. This is a feature that I think can make a system great. Keeping the UI updated with the most current information can be a great benefit. If a user A is reviewing a customer order and user B changes the customer order, the display for user A is automatically updated. I love this concept.
I decided to test the active project list by opening up two instances of the application. I opened the list in the first instance. I added a new project in the second instance. It did not automtically refresh the first instance. I added another project in the first instance, and the display was refreshed, properly showing all the projects.
Every time I have read about the MVC and Observer patterns, the examples have always dealt with “in-process” notifications. I want to cross that boundary! I’ll be looking at the project code over the weekend and try to figure out how it could be modified to register Observers from other processes (and other computers). I think the biggest design decision will be the how to change the communication channel. Isn’t this just like a chat program under the covers?
In an ideal world, all business objects would be synchronized with each other. With CSLA.NET, what would be a good way to handle notifying other objects that an object has changed?
The best idea I can think of is to have a central “change message” queue. In its simplest form, all clients would register with the central message server. When they receive events, they would determine whether the message was meant for them or not. If it was, they can iniitate whatever action is necessary to deal with the change.
When dealing with child collections (say lines on an order), we often want the parent object to take action when changes occur in the child object.
Check out this discussion.
One of the issues we have to deal with when implementing CSLA.NET is generating business code for all the existing database tables in the system. Much of this business code is repetitive and formulaic. A code generator would be very helpful.