Thursday, November 15, 2007
« Primary motivations to move from 2- to 3... | Main | Barcelona User Group & Live Meeting »

I'm busy getting my work and home life in order, as I head off to Barcelona with my oldest son for a week. I'm speaking at the Barcelona .NET user group on Wednesday, 21 November, so if you are in the area stop by and say hello! Otherwise, we'll be around the Barcelona area, enjoying Spain - I really love Spain!

Some of what I'm busy trying to get organized are some of the upcoming changes to CSLA .NET in version 3.5. Thematically of course, the focus is on support for LINQ, primarily LINQ for Objects (like CSLA objects) and LINQ for SQL. As usual however, I'm also tackling some items off the wish list, and making other changes that I think will make things better/easier/more productive - and some that are just fun for me :)

When talking about LINQ for Objects, there are a couple things going on. First, Aaron Erickson, a fellow Magenicon, is incorporating his i4o concepts into CSLA .NET to give CSLA collections the ability to support indexed queries. Second, there are some basic plumbing things that need to happen for LINQ to play well with CSLA objects, most notably ensuring that a result (other than a projection) from a query against a CSLA collection results in a live, updatable view of the original collection.

By default LINQ just creates a new IEnumerable list with the selected items. But this can be horribly unproductive, because a user might add a new item or remove an existing item from that list - which would have no impact at all on the original list. Aaron has devised an approach by which a query against a BusinessListBase or ReadOnlyListBase will result in a richer resulting list, that is still connected to the original - much like SortedBindingList and FilteredBindingList are today. This way, when an item is removed from the view, it is also removed from the real list.

Back to the i4o stuff, allowing indexing of properties on child objects contained in a list can make for much faster queries. If you only do a single query on a list it might not be worth building an index. But if you do multiple queries to get different views of a list (projections or not), having an index on one or more child object properties can make a very big performance difference!

When talking about LINQ for SQL, the focus is really on data access. LINQ for SQL, in the CSLA world-view, is merely a replacement for ADO.NET. The same is true for the ADO.NET Entity Framework. Architecturally, both of these technologies simply replace the use of a raw DataReader or a DataSet/DataTable like you might use today. Alternately, you can say that they compete with existing tools like nHibernate or LLBLgen - tools that people already use instead of ADO.NET.

In short, this means that your DataPortal_XYZ methods may make LINQ queries instead of using an ADO.NET SqlCommand. They may load the business object's fields from a resulting LINQ object rather than from a DataReader. In my testing thus far, I find that some of my DataPortal_Fetch() methods shrink by nearly 50% by using LINQ. That's pretty cool!

Of course nothing is faster than using a raw DataReader. LINQ loads its objects using a DataReader too - so using LINQ does incur overhead that you don't suffer when using raw ADO.NET. However, many applications aren't performance-bound as much as they are maintenance-bound. That is to say that it is often more important to improve maintainability and reduce coding than it is to eek out that last bit of performance.

To that end, I'm working on enhancing and extending DataMapper to be more powerful and more efficient. Since nHibernate, LINQ and ADO.NET EF all return data transfer objects or entity objects, it becomes important to be able to easily copy the data from those objects into the fields of your business objects. And that has to happen without incurring too much overhead. You can do the copies by hand with code that copies each DTO property into a field, which is fast, but is a lot of code to write (and debug, and test). If DataMapper can do all that in a single line of code that's awesome, but the trick is to avoid incurring too much overhead from reflection or other dynamic mapping schemes.

One cool side-effect of this DataMapper work, is that it will work for LINQ and EF, but also for XML services and anything else where data comes back in some sort of DTO/entity object construct.

There are also some issues with LINQ for SQL and context. Unfortunately, LINQ's context object wasn't designed to support n-tier deployments, and doesn't work well with any n-tier model, including CSLA. This means that LINQ doesn't/can't keep track of things like whether an object is new/old or marked for deletion. On the upside, CSLA already does all that. On the downside, it makes doing inserts/updates/deletes with LINQ for SQL more complex than if you used LINQ in the simpler 2-tier world for which it was designed. I hope to come up with some ways to bridge this gap a little so as to preserve some of the simpler LINQ syntax for database updates, but I'm not overly confident...

I'm also doing a bunch of work to minimize and standardize the coding required to build a business object. Each release of CSLA has tended to standardize the code within a business object more and more. Sometimes this also shrinks the code, though not always. At the moment I'm incorporating some methods and techniques to shrink and standardize how properties are implemented, and how child objects (collections or single objects) are managed by the parent.

By borrowing some ideas from Microsoft's DependencyProperty concept, I've been able to shrink the typical property implementation by about 35% - from 14 lines to 9:

Private Shared NameProperty As PropertyInfo(Of String) = RegisterProperty(Of String, Customer)("Name")
Private _name As String = NameProperty.DefaultValue
Public Property Name() As String
  Get
    Return GetProperty(Of String)(NameProperty, _name)
  End Get
  Set(ByVal value As String)
    SetProperty(Of String)(NameProperty, _name, value)
  End Set
End Property

Unlike a DependencyProperty, this technique continues to use a strongly typed local field, which I think is a better approach (faster, though slightly less abstract).

Child objects are similar:

Private Shared LineItemsProperty As PropertyInfo(Of LineItems) = RegisterProperty(Of LineItems, Order)("LineItems")
Public ReadOnly Property LineItems() As LineItems
  Get
    If Not ChildExists(LineItemsProperty) Then
      SetChild(Of LineItems)(LineItemsProperty, LineItems.NewList())
    End If
    Return GetChild(Of LineItems)(LineItemsProperty)
  End Get
End Property

In this case the implementation is more similar to a DependencyProperty, in that BusinessBase really does contain and manage the child object. There's value to that though, because it means that BusinessBase now automatically handles IsValid and IsDirty so you don't need to override them. The next step is to make BusinessBase automatically handle PropertyChanged/ListChanged/CollectionChanged events from the child objects and echo those as a PropertyChanged event from the parent. Along with that I'll also make sure that the child's Parent property is automatically set. This should eliminate virtually all the easy-to-forget code related to child objects - resulting in a lot less code and much more maintainable parent objects.

As I noted earlier, there are a lot of things on the wish list, and I'll hit some of those as time permits.

One item that I've done in VB and need to port to C# is changing authorization to call a pluggable IsInRole() provider method, allowing people to alter the algorithm used to determine if the current user is in a specific role. The default continues to do what it has always done by calling principal.IsInRole(), but for some advanced scenarios this extensibility point is very valuable.

Beyond that I'll hit items on the wish list given time and energy.

However, I need to have all major work done on 3.5 by the end of January 2008, because I'll start working on Expert 2008 Business Objects, the third edition of the Business Objects book for .NET, in January. The tentative plan is to have the book out around the end of June, which will be a tall order given that it will probably expand by 300 pages or so by the time I'm done covering .NET 3.0 and 3.5...

Now I must do some packing, and get into the mindset required to survive 11 hours in the air - they just don't make airplane seats for people who are 6'5" tall.


Thursday, November 15, 2007 11:38:55 PM (Central Standard Time, UTC-06:00)
"If DataMapper can do all that in a single line of code that's awesome, but the trick is to avoid incurring too much overhead from reflection or other dynamic mapping schemes."

Why don't you borrow some ideas from NHibernate regarding the dynamic access of properties and fields. They use a technique which is way faster than the standard reflection based access...! I'd REALLY love to see to happen the mapping of my DTO's to the BO's and vice versa in a single line of code! I'm currently using NHibernate/ActiveRecord for data access and do the mapping by hand.
Gabriel Schenker
Friday, November 16, 2007 1:37:01 PM (Central Standard Time, UTC-06:00)
"Second, there are some basic plumbing things that need to happen for LINQ to play well with CSLA objects, most notably ensuring that a result (other than a projection) from a query against a CSLA collection results in a live, updatable view of the original collection."


You may find SyncLinq interesting from here: http://www.paulstovell.net/blog/index.php/why-synclinq-should-matter-to-you/

Cheers,
Kevin
Kevin Dan
Monday, November 19, 2007 9:53:24 AM (Central Standard Time, UTC-06:00)
I don't have good knowledge on Microsoft's DependencyProperty. However, for RegisterProperty, I am thinking if it is possible to further simplify the code by providing an "alternative" through the use of attribute. Thus, might help to eliminate too many static/instance variables in a class. For example,

[PropertyInfoAttribute<string, Customer>("Name")]
private string _name = String.Empty;

public string Name
{
get { return GetProperty<string, Customer>("Name", _name); }
set { SetProperty<string, Customer>("Name", _name, value); }
}


Regards,
William
William
Monday, November 19, 2007 11:04:18 AM (Central Standard Time, UTC-06:00)
By using an attribute, you have (unfortunately) eliminated the primary purpose behind doing this, which is to remove the use of string literals throughout the code :) At the moment, RegisterProperty() doesn't actually "register" anything, it just creates a PropertyInfo object for you to use in place of a string literal (anywhere you'd use the property name or friendly name).

Ultimately, getting rid of those damn string literals is a hard thing. You can use a constant, an enum or a field. The constant and enum approaches are OK, but only get the property name, not the friendly name. And you can't put the friendly name into a costant/enum and still do localization.

So that only leaves the field approach. To avoid the perf/memory issues of creating these fields per-instance, this approach creates them at a static/Shared level.

Even that has issues with localization on a server that might be shared across many cultures, and so in that case you may be forced to use instance fields instead of Shared/static fields...
Wednesday, November 21, 2007 6:38:16 PM (Central Standard Time, UTC-06:00)
My concern is that it will introduce additional boilerplate code to CSLA business object development that a business developer needs to deal with. For example, the idea for static authorization methods CanRead(), CanDelete(), CanExecute(), etc. Although these are optional to business objects, it is good, if possible, to have these standard methods available in all business objects through inheritance. However, it is not possible because they are static methods, which forces the developer to explicitly write them manually using a consistent naming convention. Similarly, for the case of PropertyInfo object, developer needs to explicitly declare two variables per property as a "rule", although this is strictly optional.
William
Sunday, November 25, 2007 11:21:27 AM (Central Standard Time, UTC-06:00)
>> nHibernate, LINQ and ADO.NET EF all return data transfer objects or entity objects

I know there are many terms used to mean different things, and we don't have a singular dictionary for terms that everyone can agree on. When I read "data transfer object", I think of a "value object" (as defined by Fowler) where there are merely fields and no behavior, an object who's only purpose is to hold some state (no behavior). When I read "entity" in the data modeling term, this refers to state as well because data is just that, but when I read "entity" in the OO sense, I think of an object which has a unique identity regardless of what other behavior and information it hides. In other words, in OO, data transfer object and entity are two very different and distinct things. I don't have my own words for these, but I prefer to use terms in public research and writings.

I won't speak for Linq2Sql or EF, but NHibernate works off of what you tell it to. There is no restriction to working with dto's or domain objects (Eric Evans), which is the term many people (myself included) use for "business objects".

In my use of NHibernate, I map my domain objects to my database. They have different structures than the database tables, but that is where the flexibility of an ORM comes into play. If I needed data tables, I'd use data tables. I need objects, so NHibernate transforms the structure. There is lots of business logic inside the domain objects according to the responsibility of each.

I suppose one _could_ map data transfer objects using NHibernate, but it would be a waste. There are probably much better solutions for getting relational data into data transfer objects than NHibernate. The point of NHibernate is do map rich domain objects to a relational database.

All ORMs are not the same, and NHibernate (and Java's Hibernate) take the approach that a domain model is the most effective pattern for use with it. Others have a different take and are more data-centric (while NHhibernate is unabashadly an object-bigot). Linq2Sql, for instance, is very data centric. It pushes you to generating classes from the data schema instead of creating the database schema from the object model. Both approaches are valid in different scenarios, but the products are made with very different leanings.
Monday, November 26, 2007 3:56:27 PM (Central Standard Time, UTC-06:00)
Thanks Jeffrey, my personal knowledge of nHibernate is relatively limited and comes from discussions on the CSLA forum. All those discussions center around using nHibernate as an ORM/DAL behind CSLA objects.

My guess is that, because CSLA is purely and only focused on making rich domain objects, it provides a better experience for domain object creation, and nHibernate ends up providing a better experience for data access - but that's supposition on my part.

Regardless, a number of people do use nHibernate as a DAL behind CSLA objects, and what I'm doing with the DataMapper has the potential to make their lives easier. Any ORM/DAL type thing that produces objects (DTO, Entity or whatever) that a person wants to use should benefit.

And on the SOA side of things, those DTO/message objects that come and go over the wire should be easier to map into real domain/business objects in the service implementation with these changes. So the DataMapper work is a double-win in that regard.
Wednesday, November 28, 2007 10:57:54 AM (Central Standard Time, UTC-06:00)
Rocky, I didn't realize you were 6'5" as well. I feel your pain when trying to squeeze into a coach seat (or as I call it "btc", "behind the curtain").

When folks comment how "lucky" I am to be tall, I remind them about how it has it drawbacks such as finding clothes that fit or sitting in an airplane/car seat.
Bryan
Comments are closed.