February 2005 - Posts
The big buzz coming is the March CTP Release of
Indigo, one of the three two :) pillars of Longhorn. I'm
going to be gathering some posts in this entry from around the blogosphere in
hopes of relieving my brain of some more details. In addition I won't have to
save these links on my machine which gets repaved every three months or so.
News Flash
The Beta1 RC of Avalon & Indigo has been released to the wild, thanks to Drew Marsh for the link, you can get the direct download here Supposedly it will be available via this page.*
Blog Entries
Indigo Blogs
Resources
Articles
Samples
Podcasts
- .NET
Rocks Mood Indigo* (April 2005) -
Carl talks with Richard Turner and
Anand Rajagapolan, Program Managers on the Indigo team to really dig
into the Indigo experience.
Videos
-
BizTalk Server and Indigo* (May 2005) MSDN
TV - Scott Woodgate shows a glimpse into the future with a working
prototype demo illustrating BizTalk Server and "Indigo" working
together.
-
Indigo Security in a Nutshell* (April 2005)
MSDN TV - Doug Purdy provides an overview of the Indigo Security
Programming Model.
-
Introduction to Indigo* (April 2005) MSDN
TV - Steve Swartz provides a brief conceptual overview of Indigo, walks
through some code, and introduces you to his jackalope.
- Via Gene Webs blog entry:Indigo Webcasts including a) Programming Indigo 1, b) Programming Indigo 2, c) Indigo Security, d) Reliability, e) Tooling for Distributed Applications, f) The IT Pro Experience, g) Migration, Upgrade, Integration, Interop, h) Basics, i) Indigo Internals 1, j) Indigo Internals 2.
- Don Box -
Final Part of Indigo Team Tour via Channel 9 (Sep. 2004)
- Don Box -
Tour of Indigo Team via Channel 9 (Aug. 2004)
-
Service Orientation and Today's Technologies via MSDN TV (Aug. 2004)
-
The Road to Indigo Technology Roadmap
Conference Sessions
*Updated Entries. If you know of an Indigo resource or blog (preferably with an Indigo category, please send me a note. Also a comment was made that anything written prior to Feb 05 should be disregarded since these papers will have been written about a very, very different Indigo and may end up being more confusing than useful!
I just spent twenty minutes trying to track down this article in my blog clippings. I'm posting it here so I can find it a little faster next time.
Nils Jonsson created a utility class for simplifying
argument checking. The post that triggered my search for this article was K. Scott Allen's entry on
argument checking in the Enterprise Library blog entry.
In comments to my article on
Optimizations in Complex Object Creation,
Frans Bouma suggests altering my query
to use subqueries for the selecting the data rather than inner joins. I must
confess, that I am not the all knowing Sql guru, so I appreciate the feedback,
and it certainly makes sense.
To quote from his comment...
Method 2 is often the slowest. If you have 10 wines for a producer and per
wine 10 varieties, you have 1 + 10 + 10*10 queries.
If you use:
fetch the wines.
Use the wines WHERE clause as the where clause for a subquery to fetch the
winevarietal rows and use THAT where clause as the where clause for the subquery
for varietal, you'll get 3 queries.
Then merge the results in memory, which is very straight forward. This is
different from method 3 in that you don't pull a lot of data you don't want with
the join, as joins can produce a lot of redundant data. |
Well, wouldn't you know it, I'm using the slowest method currently. But
again, it all depends how I want to use the data, let's say I don't want to lazy
load the information, Frans suggests redoing my Select cause. So, after doing
that, I now have something like this, that I can use for Method 3, which should
reduce the amount of data coming back.
SELECT Wine.Id, Wine.ProducerId, Wine.Name, Wine.Vintage, Varietal.Name, WineVarietal.Percent
FROM Varietal,
(SELECT * from winevarietal,
(SELECT * from Wine Where wine.producerid=[@producerId)
WHERE winevarietal.wineId = Wine.id) As WineSubQuery
WHERE ((([WineVarietal].[VarietalId])=[Varietal].[Id]))
ORDER BY Wine.Id; |
Dru, comments as to why I don't return a DataSet/DataTable to get all of the
data and then populate my objects.
My answer is that there is no reason that I couldn't, and in fact I have some
methods in my IWineProvider interfaces that return the results as a DataSet.
It's just that I don't need (right now) the extra overhead of a DataSet in
loading my objects. And again, I can choose to modify the underlying methods as
I or other people suggest improvements (as well as using the Sql suggestions).
So, Frans & Dru and anyone else thanks for the feedback, and if I missed the
point you were trying to make, please let me know.
In comments to my article on
Handling Complex Objects in the GridView Control, Eric Wise mentions that
one needs to be careful about
Handling Complex Objects in Grids capabilities with complex objects. Why? If
I understand correctly, it's a database issue. You want to avoid loading up all
of that information up from the database unless your really want to.
He proposes two alternatives
- Expose inital load methods that make the huge database call and
prepopulate the referenced objects in one shot.
- Expose domain level queries that execute single sql statements and
return datatables.
I'm going to explore method 1 in this post, because I can already use method
2 with my object model. I simply don't include those properties in my binding
list that require complex types. Unless I'm missing something, I don't see any
advantages of method 2 over this solution. I can then drill down from the
summary information as needed to the detail. This is known as
Lazy Loading.
So, with the assumption (mine), that I can do method 2 above with my current
object model, and still retain a level of separation, let's look at how we can
improve the data loading, *if* we've decided that we *do* want to display
"complex" objects on the GridView.
One way to optimize the object loading would be to reduce the number of times
we go to the database. Here's a layout (via Access) of my data tables.

If I wanted to load all of the Wines associated with a Producer, I
could do it via the following methods
- Return a DataReader of Wine records, and then lazy load the WineVarietal
(and Varietal) records in another DataReader as needed
- Return a DataReader of Wine records and for each one get another
DataReader to load the associated Varietal information
- Return a DataReader of Wine records with multiple INNER JOIN's and
iterate through the records building the Wine and Varietal information
- Issue a batch of Sql Statements for each set of information and use the
IDataReader's
NextResult()
method to advance the DataReader to the next result set while building the
Wine and Varietal information.
I'm currently using method 2. And it goes something like this:
Get the WineDataProvider
Get an IDataReader from the WineDataProvider for all the Wine produced by the specified Producer.Id
For each record in the IDataReader
Build a Wine instance from the IDataReader
Get the VarietalDataProvider
Get an IDataReader from the VarietalDataProvider for the current Wine.Id
For each record in the IDataReader
Build a Varietal instance and add it to the Varietals collection
Add the Wine to the collection
Return the collection of Wines
Method 1 (Lazy Load) would look very similar to Method 2, with the exception
that the second IDataReader would be delayed until the Varietals collection was
accessed. In my GridView example, it would be deferred until I bound the Wine
instance to the row and accessed the Varietal collection in the <ItemTemplate>.
So, again I would expect very similar performance. Of course you don't know
until you measure right!
Method 3 would retrieve all the necessary information in one database
call. The stored procedure would something like this. Now, there's most likely
some optimizations that I can make to the stored procedure, but that's not the
purpose of this post. This would give me all of the Wines for a particular
Producer. In fact it would give me multiple records for a Wine if the wine had
multiple Varietals.
SELECT Wine.ProducerId AS ProducerId, Max(Wine.Id) AS WineId, Max(Wine.Name) AS WineName, WineVarietal.Percent, Varietal.Name
FROM Varietal
INNER JOIN ((Producer INNER JOIN Wine ON Producer.Id = Wine.ProducerId)
INNER JOIN WineVarietal ON Wine.Id = WineVarietal.WineId) ON Varietal.Id = WineVarietal.VarietalId
GROUP BY Wine.ProducerId, WineVarietal.Percent, Varietal.Name
HAVING (((Wine.ProducerId)=[@producerId])); |
Some sample output for the above statement could look something like this
Query1
|
ProducerId |
WineId |
WineName |
Name |
Percent |
|
181 |
1 |
2001
Ravenswood Winery Shiraz-Cabernet |
Cabernet
Sauvignon |
75 |
|
181 |
1 |
2001
Ravenswood Winery Shiraz-Cabernet |
Shiraz |
25 |
|
181 |
82 |
2000
Ravenswood Winery Pickberry Vineyards Sonoma Mountain |
Merlot |
53 |
|
181 |
82 |
2000
Ravenswood Winery Pickberry Vineyards Sonoma Mountain |
Cabernet
Sauvignon |
45 |
|
181 |
82 |
2000
Ravenswood Winery Pickberry Vineyards Sonoma Mountain |
Cabernet Franc |
2 |
So, now my logic for building up an instance of a Wine would look something
like this
For each record in the IDataReader
If the WineId = current Wine instance Id
Build a Varietal instance and add it
to the Varietals collection
else
Build a Wine instance from the IDataReader
Add it to the Wine collection
Build a Varietal instance and add it
to the Varietals collection
Return the Wine collection
Again, check my logic, but you get the idea. Here we tradeoff making a database
call for every object and instead load it up all at once.
Finally Method 4
John Kilgo discusses using the IDataReader.NextResult() method
here. In this
method I would forego the inner joins of the previous example and instead issue
2 selects, 1 to retrieve the Wine records, and the second to retrieve the
Varietal records. I would imagine the logic would go something like this
For each record in the IDataReader
Build a Wine instance and add it to the collection
Advance the IDataReader to the next result set
For each record in the IDataReader
Retrieve the Wine instance from the Wine collection based on
the Wine.Id
Build a Varietal class and add it to the Varietals collection
Some optimizations can be made to the above code as well
Conclusion
As you can see there are many different ways to handle the data, it all depends
on how you are going to use it. In fact you could implement the data retrieval
algorithms based on a strategy pattern, then once you understand what method
works best for a specific situation, you simply adjust the data retrieval
strategy.
Did I mention how much I love blogging? It's great to get feedback. It's the one
thing I've missed since I took about 5 months off. Did I mention I'm starting
back to work on Monday? Yup.
The new GridView in Asp.Net 2.0 makes displaying business objects just as
easy as displaying DataSets. However when it comes to displaying complex
business objects (my definition) it isn't that apparent (at least to me) how to
go about doing this.
When I say complex business object, I mean a business object that is composed
of more than just properties of simple types (int, string, etc), but instead has
properties consisting of other objects or even collections of objects. A prime
example of this in my case is the Wine class.

In the class diagram above, you can see that the Wine has a Varietals
property that is a collection of WineVarietal classes, in turn, the WineVarietal
class is composed of an Id, Percent, and a Varietal class. We're talking
complex, not rocket science, but complex. The Class diagram illustrates how I
chose to model the relationship of a Wine to it's Varietal. In this case a Wine
can be composed of one or more varietals of grape in varying percentages. Please
see my
Varietal is the Spice of Life for more details on the modeling.
In the declaration of the .aspx page GridView control, I have the following
fields bound. Notice the Varietals field, it's the same as all of the others.
<asp:gridview id="wineGridView" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField HeaderText="Id" DataField="Id" SortExpression="Id"></asp:BoundField>
<asp:BoundField HeaderText="Vintage" DataField="Vintage" SortExpression="Vintage"></asp:BoundField>
<asp:BoundField HeaderText="Name" DataField="Name" SortExpression="Name"></asp:BoundField>
<asp:BoundField HeaderText="Appellation" DataField="Appellation" SortExpression="Appellation"></asp:BoundField>
<asp:BoundField HeaderText="Varietals" DataField="Varietals" SortExpression="Varietals"></asp:BoundField>
</Columns>
</asp:gridview> |
However the GridView will display the following. See how the Varietals column
simply outputs the class name of the field. What I would really like to do is
have it display the list of varietal components, along with there percentage
makeup.
| Id | Vintage | Name | Appellation | Varietals |
| 82 | 2000 | 2000 Ravenswood Winery Pickberry Vineyards Sonoma Mountain | Sonoma Mountain | Lorengo.VirtualCellar.Business.WineVarietalCollection |
It turns out that the GridView supports the concept of a <asp:TemplateField>
which allows for the customization of the output. What I will need to do is
replace the <asp:BoundField> for the Varietals property, and instead insert a <asp:TemplateField>.
Inside of the <asp:TemplateField> I will add a DataList control, and give it an
id="varietalDataList". For the <ItemTemplate> in the DataList I will use the
Container.DataItem property, which should point to a WineVarietal item in my
Varietals collection. I can then cast the DataItem to the appropriate type.
For example ((WineVarietal)Container.DataItem).Percent will give me the
percentage of the grape varieatal in the current wine. See the code below.
<asp:gridview id="wineGridView" runat="server" AutoGenerateColumns="False" OnRowDataBound="WineGridView_RowDataBound">
<Columns>
<asp:BoundField HeaderText="Id" DataField="Id" SortExpression="Id"></asp:BoundField>
<asp:BoundField HeaderText="Vintage" DataField="Vintage" SortExpression="Vintage"></asp:BoundField>
<asp:BoundField HeaderText="Name" DataField="Name" SortExpression="Name"></asp:BoundField>
<asp:TemplateField HeaderText="Varietals" SortExpression="Varietals" >
<ItemTemplate>
<asp:DataList id="varietalDataList" runat="server">
<ItemTemplate>
<%# ((Varietal)((WineVarietal)Container.DataItem).Varietal).Name %>
(<%# ((WineVarietal)Container.DataItem).Percent %>%)
</ItemTemplate>
</asp:DataList>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Appellation" SortExpression="Appellation"></asp:BoundField>
<asp:BoundField HeaderText="ItemState" DataField="ItemState" SortExpression="ItemState"></asp:BoundField>
</Columns>
</asp:gridview>
|
Ahh, but how does it know to bind the items in the DataList to the
WineVarietal object of the current wine? You may have noticed the added
attribute in the <asp:GridView> control. To be more specific,
OnRowDataBound="WineGridView_RowDataBound".
This let's us add some special code to handle the wiring up of the Wine's
Varietals collection in the pages codebehind.
protected void WineGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
Wine w = null;
GridViewRow r = e.Row;
if (r.DataItem != null) // Make sure we're not in the Header or Footer row
{
w = r.DataItem as Wine;
}
DataList varietalDataList = e.Row.FindControl("varietalDataList") as DataList;
if (varietalDataList != null && w != null)
{
varietalDataList.DataSource = w.Varietals;
varietalDataList.DataBind();
}
|
For each row in the GridView (including the Header and Footer rows), we will
find "varietalDataList" control and update it's DataSource to the Varietals
collection of the current Wine object. Then we call it's DataBind() method and
woo hoo! Here's what we get!
| Id | Vintage | Name | Varietals | | ItemState |
| 82 | 2000 | 2000 Ravenswood Winery Pickberry Vineyards Sonoma Mountain |
| Merlot (53%) |
| Cabernet Sauvignon (45%) |
| Cabernet Franc (2%) |
| Sonoma Mountain | Clean |
I like it. Now, I'm not sure if this is the best way to do it. It just works
for me. If anyone has any other suggestions as to accomplish this, I would sure
be interested in hearing about it. My next step is to code up a general Producer
and Wine search page, so I'll take what I've learned today and apply it to those
pages.
In order to take advantage of the new GridView control in Asp.Net 2.0, I've
been researching how too use the new ObjectDataSource control, and add support
for it in my Virtual Cellar application. I now have two classes in the Virtual
Cellar Model that will serve as the candidate classes for use as an
ObjectDataSource. A lot of Asp.Net 2.0 examples use the SqlDataSource control to
illustrate the GridView features, this entry will list some resources that
specifically apply to using the ObjectDataSource
As I mentioned in my last post, I was trying to determine how to prevent the
GridView from being populated on the first page load. I found the following note
in the ObjectDataSource documentation.
The
ObjectDataSource
control retrieves data whenever the
Select
method is called. The
Select
method is automatically called by controls bound to the
ObjectDataSource
when their DataBind method is called. If
you set the DataSourceID property of a
data-bound control, the control automatically binds data when a Web page loads.
However, if you set the DataSource
property, you must explicitly call the DataBind
method of the data-bound control. You can call the
Select
method programmatically at any time to retrieve data.
So, it turns out that specifying the DataSourceId property autobinds the
control. This is more of that "no-code" model in Asp.Net 2.0. In order to
suppress the autobind, I simply removed the DataSourceId attribute from my .aspx
page. This prevents the GridView from being populated on the page load. It also
removes the link between the GridView and the ObjectDataSource, so I now have to
setup a TextChanged handler do to the binding.
protected void ProducerSearchTextbox_TextChanged(object sender, EventArgs e)
{
producerGridView.DataSource = producerDataSource1;
producerGridView.DataBind();
} |
The above snippet sets the DataSource property to my ObjectDataSource
control's Id property. This is equivalent to setting the DataSourceId =
"producerDataSource1" property in the .aspx page, except that it doesn't
autobind on page load. Then I call the DataBind() method.
I refactored a lot of the Repository code right out of my model. My reason
for doing this was to satisfy a requirement that the ObjectDataSource have a
parameterless default constructor. It turns out that you can overcome this
requirement by handling the ObjectCreating event on the ObjectDataSource and
performing my own construction. As it turns out, the new code model seems to fit
better, and I eliminated a lot of classes that I just don't need yet if ever. My
new class diagram looks like this.

Bigger picture here
The WineDataSource and ProducerDataSource replace the WineRepository and
ProducerRepository classes. The Builder classes are responsible for creating
actual instances of the Wine and Producer classes, thereby segregating the
responsibilities of each class. In order to make the *DataSource classes more
friendly to the DataSource configuration wizard, I've decorated them with the
following attributes.
[DataObject]
public class WineDataSource
{
public WineDataSource()
{
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public IList<Wine> SelectByProducerId(int id)
{
return GetWineList(this.wineProvider.GetByProducerAsDataReader(id));
}
[DataObjectMethod(DataObjectMethodType.Select)]
public IList<Wine> SelectById( int id )
{
return GetWineList(this.wineProvider.GetAsDataReader(id));
}
//...
} |
The DataObject attribute on the class level tells the wizard that this is a
DataSource class. The DataObjectMethod attribute exposes the
SelectByProducerId(int id) as a DataObjectMethod, and more specifically a
"Select" method. The second boolean argument specifies that this is the default
"Select" method. Here's how it looks in the designer.

The only items that will display in the drop down list are those that have
been marked with the [DataObject] attribute (as long as the Show only data
components checkbox is selected). This eases the clutter when your project
consists of a lot of classes.
The next step is to choose the Select method. Again, only those methods with
a DataObjectMethod and a DataObjectMethodType of Select will be shown.

In conclusion, I've illustrated how to prevent the autobinding from occurring
on the page, refined my class diagram to reflect the addition of the new
xxxxDataSource classes, and demonstrated the use of the DataObject attributes
(which are in System.ComponentModel).