How to implement an editable collection whose child's properties are known at runtime and binding it to a Silverlight DataGrid

How to implement an editable collection whose child's properties are known at runtime and binding it to a Silverlight DataGrid

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


OscarLauroba posted on Monday, March 14, 2011

I would like to use csla 4.1 for my silverlight application. Let's imagine that my MyEditableList.DataPortal_Fetch() is something like this:

Public Sub DataPortal_Fetch(ByVal tableName As String)
   Using ctx = ConnectionManager(Of SqlCeConnection).GetManager("LocalDb")

       Using cm = ctx.Connection.CreateCommand()
          cm.CommandType = System.Data.CommandType.Text
          cm.CommandText = "Select * From " & tableName

           Using dr = cm.ExecuteReader()
             While dr.read()
                Me.Add(DataPortal.FetchChild(Of MyChildEdit)(dr)
             End While
          End Using 

       End Using
    End Using

End Sub

The dataReader gets the columns of the table passed in the tableName parameter.
At this point, the problem is: How can I load de child class if I don't know the properties it will have?

For me this is a very common requirement (everything would be so easy if were known at desing time), but didn't find any sample.

Child_Fetch() should create a property for each column of the dataReader and load its value, so when I bind the EditableList to the DataGrid, each dynamic property of the child is a column of the dataGrid. How can I create a collection of properties for this editable child using csla 4.1?

RockfordLhotka replied on Monday, March 14, 2011

First, you need to identify how the Silverlight datagrid discovers properties. All the datagrid controls use reflection. Most of the Windows client datagrids also use an ICustomTypeDescriptor interface (but not Silverlight).

Then, you need to implement a subclass of BusinessBase<T> that can dynamically create properties in a way that the SL datagrid can understand. As I say, that's different for SL than it is for .NET code - and I think it involves the use of the C# 4 dynamic keyword. I am not sure if VB 10 added an equivalent to the dynamic keyword?

Once you've got that sorted out, you'll need a way to register the dynamic properties with CSLA. Basically you'll need to call RegisterProperty for each of the properties as you load them in DataPortal_Fetch, and in OnDeserialized. BUT YOU CAN ONLY DO THIS ONCE PER TYPE.

So if the shape of the objects changes on a per-query basis, you'll need to actually create a different class type each time. You can do that with dynamic too - but in that case you'll need to use the ObjectFactory data portal model, instead of the DataPortal_XYZ model. If you use the ObjectFactory model, you have more control over the specific object returned from a data portal fetch operation.

OscarLauroba replied on Tuesday, March 15, 2011

Thank you very much, Rocky, for your rapid response.

Certainly, the fields returned by the sql sentence are different for each table.
Some of them have columns in common, but I can't assume this for all the tables.
Our customers can add the columns they need to their tables. they even can add new tables. In fact, I don't know the  fields' structure of any table.

For instance, Select * From Persons could return three columns ; IdPerson, FirstName and SecondName, but another query Select * From Orders could return OrderId, OrderDate, CustomerId, LastEdit.
One option would be to use indexed properties. I haven't tried yet if Silverlight can bind anything that implements IEnumerable(Of IDictionary (of String, Object)).

I've been thinking if it would be a good solution -if it was possible- to use indexed properties, as some blogs propose.
How could we write indexed properties in csla 4.1 for the child class? Something like this:

   Private _data As New Dictionary(Of String, Object)()
   Default Public Property Item(ByVal nameField As String) As Object
      Get
         Return _data(nameField)
      End Get
      Set(ByVal value As Object)
         _data(nameField) = value
      End Set
   End Property

It concerns me that you say  "BUT YOU CAN ONLY DO THIS ONCE PER TYPE". Would you please expand this concept? I need only one class that could manage any table the user selects in order to edit its data. I haven't ever used the FactoryObject model. Using this model, Is it possible instantiate several objects with different lists of propertyInfos from only one businessBase class?

It would be so nice if when writing your next expected silverlight ebook you could add a little chapter dedicated to "Dynamic Properties with csla ". Smile

Oscar.

RockfordLhotka replied on Tuesday, March 15, 2011

When you use RegisterProperty to register the PropertyInfo<T> for each property of your type, those values go into a static cache for that object type. Those values can be set only once, and they must remain consistent through the application's lifetime.

Business and authorization rules are attached to those PropertyInfo<T> values, and they are used for serialization by the MobileFormatter.

You are right - it would be nice to have a chapter on dynamic properties - but that assumes I have a good answer for the problem :)

What you want is complex, because you want a type that changes with every query. So nothing is consistent, and nothing can be cached, and no instance of the type is required to look like any other instance of the type. The CSLA property registration system is not designed to handle something this fluid and unpredictable.

I think you could create a base type that would be this flexible, but it would involve recreating BusinessBase and BusinessBase<T> from scratch, and each object instance would have to manage its own metastate and property definitions - so it would be very large when serialized.

To handle the read-only scenario, in .NET, I've always recommended using the DataSet or DataTable, because those technologies are designed to support this type of flexibility.

And if your scenario is also read-only and you have no authorization rules, I think there are some relatively simple options to consider.

If your scenario is read-write, or you want to use business, validation, or authorization rules, then things are going to be difficult.

Is your scenario read-only?

OscarLauroba replied on Wednesday, March 16, 2011

No. My scenario is read-write.
I'm migrating our windows application from Vb6 to Silverlight 4. The old application is using recordsets to get this done. Precisely I wanted all the power of csla to develope our new Silverlight application in an object oriented manner.
I'm searching this dynamic behaviour of datatables for silverlight business objects. However, as far as I know, there's no datables in Silverlight.

Oscar.

tmg4340 replied on Wednesday, March 16, 2011

No - Silverlight has no System.Data namespace.  No DataTables, DataSets, Connections, etc.

I think dynamic behaviors are possible within a SIlverlight app, but as Rocky has mentioned, I don't know how well CSLA will accommodate that in its present form. 

FWIW, you aren't the first person to ask about this.  So perhaps you can take solace in the fact that you aren't alone.  Smile  But I'm not sure how Rocky would solve this kind of issue within CSLA in a manner that doesn't break a lot of what's currently in place.

- Scott

RockfordLhotka replied on Wednesday, March 16, 2011

That is the trick Scott, you are right.

I think the request here, is:

  1. For some type that allows each instance of the type to have different properties - so no two instances of the type are required to look like each other
  2. In each instance of this type, dynamically attach business, validation, and authorization rules to each dynamic property
  3. In each instance of this type, dynamically define the "per-type" (which would now be per-instance) authorization rules for create/get/edit/delete operations

Clearly this can't be incorporated into the existing base types - because each instance of this new type would be HUGE when serialized. So for normal application scenarios the performance would be horrific. Just think about loading 100 of these into a collection - where each object instance maintains all its own metadata - wow!

In fact, you really couldn't do it that way - the overhead is clearly too high.

So I think the solution would have to be something along the lines of a collection (like a DataTable) that contains the property and rule definitions for the dynamic objects it contains. So within that collection, all the objects would have to share the same shape and rules.

The overhead would still be quite high compared to the existing CSLA base classes, but at least this would be somewhat realistic in terms of loading a collection of items.

Of course the next thing someone would want is child objects, and other relationships.

In short, what we're talking about here is designing and implementing something comparable to the DataSet, but with all the rule features of CSLA.

And to that, all I can say is that I'm very happy to accept contributions to CSLA .NET, so if someone wants to build this thing, I'm open to it :)

OscarLauroba replied on Thursday, March 17, 2011

Thank you, Scott and Rocky for your contribution.
It's certainly true that not to be alone is a great comfort to me. Something like Microsoft Entity Framework is not useful for me. My application has to connect to to the databases that our costumers have. Sometimes it's SQL Server, but others is Oracle. As I said, if our customers think they need a new column or table, they feel free to add them to their database. EF has no sense. Database is also dynamic.

In my opinion, "dynamic development" also has advantages in reference to productivity. If a developer has to write n-number of properties, he has to do same operation (ctrlK + ctrlX to get the property snippet) n-times. If this properties are known at runtime, he can complete all the properties with only one For Each field In DataReaderCollectionField ...Next snippet.

I don't know if I'm using the term "dynamic" correctly, because once I know at runtime which properties the business object is going to have, these will remain static through its lifetime. Adding properties to the object is made only once. Dynamic means to me that I can add any property at any time. And that's not my scenario. So the behaviour is always the same. A query to the database tells me which properties my object will have. Then, load those properties with values, get the validations and last implement CRUD functions.

So, which classes would I have to review? I need my new DynamicBusinessBase class can have properties per "RuntimeType" instead of per Type. RuntimeType or DynamicType would have to be a key string to assign at runtime with the name of the table to access or whatever. For example, all the instances of the DynamicType "Table_Categories" will have the same signature.

Oscar.

tmg4340 replied on Thursday, March 17, 2011

Well... the way I (and I think Rocky) originally interpreted your request was that you wanted to create one business object class to cover every entity type that you have.  That is a dynamic object, since while all instances of your "Table_Categories" type would have the same set of properties, instances of "Table_Products" would have a different set of properties.  But they would all be the same class type, at least as far as CSLA and .NET is concerned.  That's a dynamic object in this sense.

Beyond that, I would like to comment that while "dynamic development" does have some productivity benefits, you are losing quite a bit too - strong typing of properties for starters.  You also have to write quite a bit of code to get .NET to play nice with these types of objects, since it can't use straight reflection to figure out the shape of your object.  And since you're working in Silverlight, I'm not exactly sure how you would go about doing that - things like DataTables implement a particular interface to get that job done, and I don't think that interface exists in SL.  There are also data-binding issues to consider as well (above and beyond what I just talked about), which likely would require more code.  Many folks would consider it a win to just create a set of properties and fall back on .NET to do the rest for them.

To start with, you'll need to look at BusinessBase<T> (and probably BusinessBase as well).  If you need collections, then you need to look at BusinessListBase (and possibly delve into one or more of its base class as well).  But realize that those classes depend on a whole other set of classes to maintain property state, authorization rules, authentication, etc.  All those are at least going to have to be looked at, since they were built to support the current CSLA model, and they very likely may need to be copied/re-worked to deal with your new object graph structure.

In the end, Rocky is right - you're basically going to be re-implementing a DataTable/DataSet, but trying to tag on all the "CSLA goodies" that you want.  And once you have it working, you're going to have to do quite a bit of performance testing to make sure that your objects don't get ridiculously huge when they're serialized (a distinct possibility that Rocky has already talked about), and that they don't slog your UI performance as well.  That is almost more than non-trivial...

HTH (and good luck!)

- Scott

Copyright (c) Marimer LLC