4.3 Using Parameters
In most cases, methods require parameters. SelectParameters
is the collection you use to add input parameters to the select method.
Imagine you have a method to load employees by country. Here’s the code
you need to come up with:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
TypeName="Core35.DAL.Employees"
SelectMethod="LoadByCountry">
<SelectParameters>
<asp:ControlParameter Name="country" ControlID="Countries"
PropertyName="SelectedValue" />
</SelectParameters>
</asp:ObjectDataSource>
The preceding code snippet is the declarative version of the following pseudocode, where Countries is expected to be a drop-down list filled with country names:
string country = Countries.SelectedValue;
EmployeeCollection coll = Employees.LoadByCountry(country);
The ControlParameter
class automates the retrieval of the actual parameter value and the
binding to the parameter list of the method. What if you add an [All Countries] entry to the drop-down list? In this case, if the All Countries option is selected, you need to call LoadAll without parameters; otherwise, if a particular country is selected, you need to call LoadByCountry with a parameter. Declarative programming works great in the simple scenarios; otherwise, you just write code.
void Page_Load(object sender, EventArgs e)
{
// Must be cleared every time (or disable the viewstate)
ObjectDataSource1.SelectParameters.Clear();
if (Countries.SelectedIndex == 0)
ObjectDataSource1.SelectMethod = "LoadAll";
else
{
ObjectDataSource1.SelectMethod = "LoadByCountry";
ControlParameter cp = new ControlParameter("country",
"Countries", "SelectedValue");
ObjectDataSource1.SelectParameters.Add(cp);
}
}
Note
that data source controls are like ordinary server controls and can be
programmatically configured and invoked. In the code just shown, you
first check the selection the user made and if it matches the first
option (All Countries), configure the data source control to make a
parameterless call to the LoadAll method.
You must clean up the content of the SelectParameters
collection upon page loading. The data source control (more precisely,
the underlying view control) caches most of its properties to the view
state. As a result, SelectParameters is not empty when you refresh the page after changing the drop-down list selection. The preceding code clears only the SelectParameters
collection; performancewise, it could be preferable to disable the view
state altogether on the data source control. However, if you disable
the view state, all collections will be empty on the data source
control upon loading.
Important
ObjectDataSource
allows data to be retrieved and updated while keeping data access and
business logic separate from the user interface. The use of the ObjectDataSource
class doesn’t automatically transform your system into a well-designed,
effective n-tiered system. Data source controls are mostly a
counterpart to data-bound controls so that the latter can work more
intelligently. To take full advantage of ObjectDataSource, you need to have your DAL already in place. It doesn’t work the other way around. ObjectDataSource
doesn’t necessarily have to be bound to the root of the DAL, which
could be on a remote location and perhaps behind a firewall. In this
case, you write a local intermediate object and connect it to ObjectDataSource
on one end and to the DAL on the other end. The intermediate object
acts as an application-specific proxy and works according to the
application’s specific rules. ObjectDataSource
doesn’t break n-tiered systems, nor does it transform existing systems
into truly n-tier systems. It greatly benefits, instead, from existing
business and data layers. |
4.4 Caching Data and Object Instances
The ObjectDataSource component supports caching only when the specified select method returns a DataSet or DataTable
object. If the wrapped object returns a custom collection (as in the
example we’re considering), an exception is thrown. Custom object
caching is something you must do on your own.
ObjectDataSource
is designed to work with classes in the business layer of the
application. An instance of the business class is created for each
operation performed and is destroyed shortly after the operation is
completed. This model is the natural offspring of the stateless
programming model that ASP.NET promotes. In the case of business
objects that are particularly
expensive to initialize, you can resort to static classes or static
methods in instance classes. (If you do so, bear in mind what we said
earlier regarding unit testing classes with static methods.)
Instances
of the business object are not automatically cached or pooled. Both
options, though, can be manually implemented by properly handling the ObjectCreating and ObjectDisposing events on an ObjectDataSource control. The ObjectCreating
event fires when the data source control needs to get an instance of
the business class. You can write the handler to retrieve an existing
instance of the class and return that to the data source control:
// Handle the ObjectCreating event on the data source control
public void BusinessObjectBeingCreated(object sender,
ObjectDataSourceEventArgs e)
{
BusinessObject bo = RetrieveBusinessObjectFromPool();
if (bo == null)
bo = new BusinessObject();
e.ObjectInstance = bo;
}
Likewise, in ObjectDisposing you store the instance again and cancel the disposing operation being executed:
// Handle the ObjectDisposing event on the data source control
public void BusinessObjectBeingDisposed(object sender,
ObjectDataSourceDisposingEventArgs e)
{
ReturnBusinessObjectToPool(e.ObjectInstance);
e.Cancel = true;
}
The ObjectDisposing event allows you to perform cleanup actions in your business object before the ObjectDataSource calls the business object’s Dispose
method. If you’re caching the business object, as the preceding code
has done, be sure to set the cancel flag so that the business object’s Dispose method isn’t invoked and the cached object isn’t as a result stored in a disposed state.