Lazy Loading Example

Lazy Loading Example

Old forum URL: forums.lhotka.net/forums/t/1799.aspx


ltgrady posted on Monday, November 20, 2006

I have a Product Object.  The object has about 350 properties.  Now before we go further let me justify that consider the threads I've ready through on the forum that pertain to lazy loading.  Each of our products has the potential to use these fields.  Shipping fields, pricing fields, sales and shipping policies, manufacturing information, electronic standards information, product dimensions and weights, etc., etc., etc..  In our industry distributors have spec sheets that may have anywhere from a half dozen to a fifty pieces of information they ask for and each sheet is different (there are over 100 spec sheets in the system currnetly and growing all the time). 

Our suppliers, who maintain their prodcut information all ask for different sets of information.  Someone selling sporting goods uses many different fields than someone selling electronics or silverware or food packages.  They're using an asp.net interface that uses dynamically built GridView bound to CSLA objects.  They select from 170 different "groupings" of these fields (the same field can be in many groups) to enter and maintain the data that they want to use.  It's a lot of information and it takes a lot of work to group it logically in a way that makes things easy for our users to find. 

We can't have a diferent object for each field group because people can create custom groups themselves with a field picker (plus there are already 170 of them).  The grids binds to the Product object that contains every field.  The Field Group they choose uses SQL data to dynamically create the GridView and validation controls which is then bound to that Product object.

We have a single field that is probalby only going to be used perhaps 20% of the time.  This field is a very complicated calculation that will require us to add three or four tables to our _Select stored procedure and use dynamic sql in the stored procedures to calculate the value.

I would REALLY like to lazy load the field so that when I call a collection of 100 products, all with those 350 fields already loading, I don't have to add this very costly field unless it's absolutely necessary.

Does anyone have a decent example of this.  I see a lot of lazy load discussion and some examples for loading a child collection (which I do elsewhere in teh app) but I'm unsure of the "right" way of going about this.  I'm not sure whether to call teh _Fetch command again when the Get on this property is called and run a different SProc, or whether to create an object whose only function is to retrieve this value and use that?  Any advice on how I should do this?

Bayu replied on Monday, November 20, 2006

How about decomposing this huge monolithic thing in a workflow?

From your story I get the impression things are spiraling out of control rapidly. And your request for a lazy-loaded property is just the first sign of much more worse stuff yet to come.

Apparently you are trying to cover ALL dynamics of your system in just 1 object and 1 view.

What if you would (massively) decompose this single view in a number of separate use cases (i.e. interaction steps) where the user gets from to the desired end-result in a step-by-step fashion ...?

With a workflow you would be able to capture the dynamics and then you can also ensure that only those (heavy-weight) routines run that actually need to run.

Bayu

Edit:
I forgot to answer your original question. Sorry for that!

You would need a local boolean variable that tells you if a particular property has been fetched from the DB yet or not. Upon first request you would execute a specific command to your DB that does what you need.

As an example, see my function that checks if a particular instance (defined by ID) exists in the DB. It uses an inner class that derives from CommandBase. Modifying it to your needs should be trivial:

    Public Shared Function Exists(ByVal id As Guid) As Boolean
        Dim result As ExistsCommand = DataPortal.Execute(Of ExistsCommand)(New ExistsCommand(id))
        Return result.Exists
    End Function

    <Serializable()> _
    Private Class ExistsCommand
        Inherits CommandBase

        Private _ID As Guid
        Private _Exists As Boolean

        Public Sub New(ByVal id As Guid)
            Me._ID = id
        End Sub

        Public ReadOnly Property Exists() As Boolean
            Get
                Return Me._Exists
            End Get
        End Property

        Protected Overrides Sub DataPortal_Execute()
            Using cn As New MySqlConnection(Database.CrmDBConnection(True))
                cn.Open()
                Using cm As MySqlCommand = cn.CreateCommand

                    cm.CommandType = CommandType.Text
                    cm.CommandText = "SELECT COUNT(CustomerID) FROM Customer WHERE CustomerID = @id"
                    cm.Parameters.Add("?id", Me._ID)

                    Dim count As Integer = CInt(cm.ExecuteScalar)
                    Me._Exists = (count > 0)

                End Using
            End Using
        End Sub

    End Class



Bayu replied on Monday, November 20, 2006

In addition to my previous post:

Last week dotnet 3.0 was released. It comes with the Windows Workflow Foundation. You might draw inspiration from it in case you would want to try out a more interactive design.

See also:
- http://wf.netfx3.com/
- http://www.netfxguide.com/

Regards,
Bayu

david.wendelken replied on Monday, November 20, 2006

ltgrady:

I have a Product Object.  The object has about 350 properties. 

Um...  Do you really have 350 properties, with 350 getters and setters? 

I'm wondering if this couldn't be designed as a collection instead of hard-coded properties.

(Or is that what you already have?)

The collection would have "Group Header" and "Field Label" and "Field Value".  The user would enter in the "Field Value".  With a bit of cleverness, the collection could actually feed a some type of tree control so the user would be able to focus on different Group Headers at a time.

This would have the advantage of being way more dynamic, as the list of Fields needed for that could be loaded in from some meta-data tables.

With the addition of a "LoadedYet" property to the collection, your UI could know whether to ask for those values to be loaded or not when the group with your "slow-loading values" gets expanded.

Copyright (c) Marimer LLC