Friday, November 6, 2009

Entity Framework & Lazy Loading

For the last 2 years I've read and read the EF team swearing by their design decision to turn lazy loading off by default. Heck they even went the extra mile to change the name and obscure the option (Deferred Loading anybody?).

I just found out, that the latest CTP has lazy loading on by default and guess what? it is actually called "Lazy Loading"...

I don't know about you, but I find all this somewhat irritating. Albeit, a bit vindicated. :D

Thursday, July 30, 2009

NHibernate, Oracle & Clobs

If you are starting to work with NHibernate and Oracle you will definitely go through a lengthy stressful process of denile, understanding and acceptance.

So here I will share a bit of knowledge that will make that process a bit less stressful.

If you are working with clobs/nclobs and oracle you may or may not have encountered the following error when using the microsoft provided system.data.oracleclient

ORA-01461: can bind a LONG value only for insert into a LONG column

This error is not very helpful and goggling it will most likely result in topics regarding oracle patches and the like. In reality this is a bug with the microsoft oracle client driver. The driver mistakenly infers the column type of the string being saved, and tries forcing the server to update a LONG value into a CLOB/NCLOB column type. The reason for the incorrect behavior is even more obscure and only happens when all the following conditions are met.

1. when we set the IDbDataParameter.Value = (string whose length is : 4000 > length > 2000 )
2. when we set the IDbDataParameter.DbType = DbType.String
3. when DB Column is of type NCLOB/CLOB

Unfortunately NHibernate 2.0's default behavior is to do exactly the above, making it quite more likely to run into this ugly bug when using nhibernate and oracle.

It is also unfortunate that the issue has indeed been raised with the NHibernate community but has been closed as external. http://nhjira.koah.net/browse/NH-465

I pretty much figure that since Microsoft has decided to pull their driver from the .NET framework in the future, they wont fix this external issue, so it becomes the burden of the developer to work around this ugly bug. So without much further ado here is the way I've gotten around fixing this issue.

I created a custom driver and inherited from the Oracle client driver where I override as follows.

/// <summary>
///
Initializes the parameter.
/// </summary>
///
<param name="dbParam">The db param.
///
<param name="name">The name.
///
<param name="sqlType">Type of the SQL.
protected override void InitializeParameter(System.Data.IDbDataParameter dbParam, string name, global::NHibernate.SqlTypes.SqlType sqlType)
{
base.InitializeParameter(dbParam, name, sqlType);

//System.Data.OracleClient.dll driver generates an exception
//we set the IDbDataParameter.Value = (string whose length: 4000 > length > 2000 )
//when we set the IDbDataParameter.DbType = DbType.String
//when DB Column is of type NCLOB/CLOB
//The Above is the default behavior for NHibernate.OracleClientDriver
//So we use the built-in StringClobSqlType to tell the driver to use the NClob Oracle type
//This will work for both NCLOB/CLOBs without issues.
//Mapping file will need to be update to use StringClob as the property type
if ((sqlType is StringClobSqlType))
{
((OracleParameter)dbParam).OracleType = OracleType.NClob;
}
}


I will try reopening this issue with the NHibernate commiters and see if it now warrants an update.

Friday, January 25, 2008

Dynamically Extending Objects in C# - Part 1

So you've finished your domain model, it is looking beautiful and performing great, but the business throws a curve ball. They need to add a couple of new fields critical to their needs, and it needs to happen yesterday.

Sure, this is not the hardest thing to do in most applications. Whip out, the mapping files, add the field to the xml, db & object and you are done.

However, this is not always the case. For example, I've recently been working in a system that does a lot of cross schema data manipulation, through batch processes and triggers. What this means is that adding a field is no easy affair. I add the field in a upstream schema/object model and then I modify the routines that move it downstream to the next schema/object model and downstream, and on, and on.

Well the idea here mostly applies to Windows Forms but it could also apply to Web Forms. By making use of the System.ComponentModel namespace, we can extend our business object's meta data at run-time and change the behavior of our databound controls.

In this manner I can add new properties to any existing type at runtime and get these to be automatically picked up by the UI controls bound to that type. Consequently, I can have the plumbing laid out in expectancy of DEFCON 1 type scenarios.

So how does it work?

If you've poked around the System.ComponentModel namespace you've probably stumbled upon this beautiful diamond named TypeDescriptor. It has methods like GetProperties(), GetEvents(), etc. TypeDescriptor basically wraps some of the System.Reflection basic constructs and adds various extensibility points which are used by controls when databinding.

For our purpose I'll concentrate in the GetProperties() method which returns a PropertyDescriptorCollection. A PropertyDescriptor exposes all the basic metadata information about a property like, PropertyType, Name, etc, along with other information like DisplayName and Description. It also has some methods to Set and Get the value of the property for an instance.

So how can we leverage this property descriptor to do our bidding? Let's say for example you have a grid bound to your object. In this case let's say it is an Infragistics UltraGrid (since I know this works in this grid). Let's take a simple scenario and say that I want to change the column names in my grid dynamically. The grid obtains the databound object column names by making a call to TypeDescriptor.GetProperties() and checks the DisplayName for each of the object's properties. Well what I want to do is obtain the name of the columns from somewhere other than the attributes on the object.

public interface IPropertyMetaDataService
{

string GetDisplayName(Type componentType, string propertyName);
...

}

Implementing this interface allows me to get a display name for a type/property name combo.

public sealed class MetaPropertyDescriptor : PropertyDescriptor
{

private PropertyDescriptor innerPropertyDescriptor;
private IPropertyMetaDataService PropService { get { return ... ;} }

public override string DisplayName
{

get
{

string displayName = null;

displayName = PropService.GetDisplayName(

innerPropertyDescriptor.ComponentType,
innerPropertyDescriptor.Name);

return string.IsNullOrEmpty(displayName) ?

innerPropertyDescriptor.DisplayName :
displayName;

}
}
...

}

And, by inheriting from Property Descriptor I can override the behavior of my databound components. Voila, now with a little more boilerplate code I can get my grid to display column names from my PropertyMetaDataService.

In the next part I'll discuss a couple more interesting things that can be done using this technique.

Thursday, January 24, 2008

The road less travelled

A couple of guys have been bugging me @ work to start a blog.

A blog technical in nature, though not guaranteed to be, about many different things that interest me as a developer. I hope this blog will keep company to people that are traveling the same road I am.

So without much further ado, here it is, the first post and first step of many to come (hopefully).