Finally Coming Home!

posted on 06/01/04 at 09:22:38 am by Joel Ross

I'm sitting in the airport, knowing my laptop will die soon. I'm in San Francisco, waiting to go home. I get to take the red eye (oh joy!), and hopefully get some sleep. Not sure how possible that will be. My last flight, I slept for about an hour. Same with my flight here.

It's a long flight from Detroit to San Fran. Especially if you are awake for it.

Anyway, we finished up another successful week out here. We changed their design the week before I came here. Instead of using typed datasets, which I wasn't completely comfortable with, we decided to go with custom objects. Something I'm much more comfortable with. Why did we make the switch? We weren't going to be using the power of them, so why deal with the overhead and the quirkiness of the dataset? When I say we wouldn't use the power, I basically mean we wouldn't be using the diff gram in it - no DataAdapter.Update() - all custom stored procedures and Command.ExecuteNonReader().

So we started Monday. We finished the database conversion, tested the script against "live data" and began creating objects. We modified a few Code Smith templates, and generated our data classes, collections and data access layer. Then we made the necessary mods to add collections where needed, as well as owners to the objects that needed them.

Do other people use owners? We had our reasons, but I typically do. That way, if I'm dealing with an OrderLine, I can just say OrderLine.Owner.Owner to get to the customer (assuming an Order owns an OrderLine and a Customer owns an Order). This way, you can move around the object model seamlessly. We had a few objects that we couldn't figure out what owned it - either it didn't make sense to have an owner, or there were multiple owners.

Then we came up with an object caching strategy, as well as a session expiry recovery scheme.

I like the session expiry scheme. Basically, the object (let's call it a customer), is cached. Then, on every page, if the object is still there, we use it. If it went away (they go away after 20 minutes), we have a way to rebuild it. Any page that deals with a Customer uses a custom base class. On (pre) render of the page, the Customer ID is shoved into viewstate. This is read from a StateManager. Then, when the page is posted back, the value in viewstate is checked against the StateManager. If they are different, then the viewstate value is put back into the StateManager.

Then we have our caching strategy. You get the CustomerId from the StateManager, and then we call the UI Process to get the Customer object. It attempts to read it from cache. If it's not there, it uses the ID to (re)build it. If it's there, it grabs it, and checks the modified date on the object to the modified date in the database. If it's different, it reloads it. If it's the same, then it returns it to the page.

By the way, I really like the idea of a UI Process Layer. More on that later.

Anyway, any sub objects on the Customer come along with it, and if they get updated, the modified date of the customer is changed. That means if you update a OrderLine, the customer's modified date is updated - this was the real reason for having an Owner object. Now, when the OrderLine is updated, the new modified date is returned by the stored procedure and shoved back into the Customer object - using the orderLine.Owner.Owner.ModifiedDate property.

On a side note, our objects aren't really a Customer, Order and OrderLine. It's completely different, and much more complex. And, we made the decision that if a sub object (even if it's way down the chain) is updated, the whole object should be invalidated. Why? The object will 99% of the time only be touched by one person at a time. The case when two people do, well, they'll just have to deal with the performance hit. And we eventually have to deal with concurrency, and how to handle that. Most likely, accessing anything related to a Customer will lock everything about that Customer.

We discussed the idea of locking a set of records (basically check-in and check-out of objects). How do you implement that? I mean, I know technically how. But logically, how should it work? Do you check it out, and if you don't touch it for a certain amount of time, then it's unlocked again? If someone else accesses it, are they denied, or just given read-only access? What if the process they are dealing with happens to take more than 20 minutes? Do they automatically get their lock back if it's not locked? What if it is now locked by someone else? What if two people use the same record, but only update different parts? This is why locking is so difficult. For now, or model is a "last in wins" model. But that will have to change.

Well, my flight is getting ready to load. Looks like a full one.

Categories: ASP.NET, Consulting