NHibernate.LINQ with ADO.NET Data Services

Silverlight Logo

Now that my ADO.NET Data Services support has been merged into the trunk of NHibernate.LINQ, I do have some caveats about using NHibernate.LINQ with ADO.NET Data ServicesADO.NET Data Services is a beta 1 product so there are some bugs and issues that you will either need to avoid or work around.

The biggest issue is around entity identity. ADO.NET Data Services must know how identity is established for objects in order to support the Data Service. It does this in a two step process:

  • First it looks for attributes that describe the 'primary key'.
  • Failing that, it looks for properties on the entity called ID, or ending with "ID".

The second approach is where I expect most of NHibernate projects to fall into since you really don't want to pollute your objects with technology specific information (the attributes). This approach works well except that there is a bug in the Beta 1 version of ADO.NET Data Services.  If the properties are specified in a base class and the keys are specified ending in "ID" (instead of just being called "ID"), then the search for the identifiers fails and Data Services fails to want to serve these objects.  For example:

public class AbstractCategory
{
  public virtual int CategoryID { get; set; }

  public virtual string CategoryName { get; set; }

  public virtual string Description { get; set; }

  public virtual byte[] Picture { get; set; }

  public virtual IList Products { get; set; }
}

public class Category : AbstractCategory
{
}
}

If this is your scenario, I might suggest waiting for later build of ADO.NET Data Services to be released as this is definitely a bug not expected behavior and I have gotten word from Microsoft that it is fixed in the RTM (which isn't available yet).

The next issue is that for collections, ADO.NET Data Services must understand the types that belong in a collection. In this case our above example will not work either in that having the Products in a Category as a simple IList can't tell ADO.NET Data Services what types of objects to deal with.  If we change this to an IList<Products>, it works fine.  If we have to change our entities to work with ADO.NET Data Services, this is what our new Category might look like instead:

public class Category
{
  public virtual int CategoryID { get; set; }

  public virtual string CategoryName { get; set; }

  public virtual string Description { get; set; }

  public virtual byte[] Picture { get; set; }

  public virtual IList<Product> Products { get; set; }
}

With these changes, ADO.NET Data Services work fine.

If you are new to ADO.NET Data Services, this blog entry may help with some debugging issues in using it:

http://wildermuth.com/2008/06/07/Debugging_ADO_NET_Data_Services_with_Fiddler2

Lastly, I want to follow up on a note that Ayende mentioned on his announcement of my examples.  In his blog post, he said:

From a technological perspective, I think this is awesome. However, there are architectural issues with exposing your model in such a fashion. Specifically, with regards to availability and scalability on the operations side, and schema versioning and adaptability on the development side.

I think he's right in that there is a schema version issue here that needs to be addressed but that the availability and scalability problems are ones that would be in the underlying data model itself. Since ADO.NET Data Services are just a convenience around WCF's REST Service Model, we can scale out or up depending on our needs (as well as caching).

What I think is important is to understand the reason behind ADO.NET Data Services.  It is not a model to replace typical Web Service or Message Bus architectures.  Its not all that fast or efficient.  Its purpose is to allow the creation of a simple model to allow communication across the firewall.  What I mean is that it is meant for the AJAX and RIA developers.  Its a way of communicating data to clients that run on the Internet. 

Its important to understand that data you expose with ADO.NET Data Services is not magically more secure...in fact, since its meant for client-side consumption of data, you should not allow data to be exposed by ADO.NET Data Services that is sensitive. Remember, that consuming data in the client is not secure in itself.  If you wouldn't feel safe consuming data in client-side JavaScript, don't expose it via ADO.NET Data Services.

Comments:

Gravatar

Hi, very nice articles! Thank you very much. I do have a question about the security issues you mention at the end. I have an application where sensible data is needed client-side (because the application is sometimes offline)... Isn't encryption of the data a posibility? Or are there caveats I'm not aware about in that scenario?

Gravatar

The general problem with encryption is where do you keep the shared secret? If you are using keys to encrypt the data but that key is in the .xap file, then I can find they key pretty easily to get at that data, especially if it is stored locally.

Gravatar

Shawn,

Nice work on the Linq implementation, I am having an issue with the Rest side of things and am new to nHibernate. The problem involves the Linq query built and passed to your Linq process, when a rest query comes in like:
http://foo//some.svc/Project?$filter=startwith(Name,'A') the Linq query looks like it has sql specific syntax (Convert(IIF( , etc). which is not recognized by the linq expression handler. Can you guide me to where the translation from the href to linq ?

Gravatar

Fars1d3r,

I have found that some basic queries in the NHibernate.LINQ implementation aren't working correctly...not sure if you're problem is about that. Have you tried that with an Entity Framework app to see if its NHIbernate specific? Also, have you tried without Data Services to see if the same query is fine directly with NHIbernate.LINQ?

Gravatar

I did some more experimenting, Convert is missing from VisitUnary - maybe it should be there, perhaps elsewhere. Once I added it I got a query to run with the filter referenced in the convert, but the IIF criterea was missing so it filtered all rows - the resultant query has two filters:

where {filterColumn is null} and { filterColumn.beginsWith('A'}

the is null is obviously conflicting and should be is not null, but that is because the IIF is not in there !

I also noted from your example site that the query

http:localhost/TheService.svc/Product(1)/Category

returns the Product rather than the category.

Gravatar

Shawn, sorry for the delay. The beginswith query works properly in nHIbernate.linq when it is built on the server, it is only the Rest generated Linq version that fails. The begins with Linq query without rest involved does not include the IIF and Convert portions. The query does work properly in the Entity Framework when coming from the rest interface. Hope this helps

Gravatar

Has anyone managed to confirm that the base class property bug has been fixed in RTM? I seem to be having this problem in VS 2008 SP1 RTM.

Pete

Gravatar

Sorry Pete, What "base class property" bug?

Gravatar

In your article you say

"If the properties are specified in a base class and the keys are specified ending in "ID" (instead of just being called "ID"), then the search for the identifiers fails and Data Services fails to want to serve these objects."

I am experiencing this in my model but it works fine when the e.g. CategoryId is in the derived class.

I also see the same thing if I try to use the interface to specify the IOrderedQueryable<ICategory>

Pete

Gravatar

Pete,

Remember this article was based on SP1 Beta so its likely they fixed this in the RTM of SP1 (which I assume you're using).

Gravatar

Well,
If you take the silverlight example at http://www.silverlightdata.com/Simple/NHibernate.aspxand just call the web service from a browser under RTM then you can see that, if you move the properties to an abstract base class then you get errors.

Seems it wasn't fixed for RTM. Just noticed this thread on msdn forums as well http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3748415&SiteID=1 which seems to point to the same thing. It would appear that this might cause a problem for some inheritance models in nHibernate.

Pete

Gravatar

Pete,

Thanks, hopefully the Data team is looking at it. Sounds like a non-Silverlight issue, right? Also, its about the query not the update? Just making sure its not my code in the IUpdateable interface that is causing the problem.

If the issue is isolated to NHibernate it might be an issue in how the Astoria query is being translated. I am going to look into this next week when I migrate a complex example over to RTM.

Gravatar

Yep,
The problem is in the service, nothing to do with the silverlight client. Specifically on the Get operation.

Pete

Gravatar

Shawn,

I think this is about the only article on the web showing ADO.NET data services with NHibernate :)

Now... the next big article needed is 'how about NHibernate with RIA.NET ?'

There is a large gap right now in the inclusion of NHibernate in many of the talks and slides (they give verbiage of 'you can use it' but no examples).

I encourage you to update this article and even look at a good 'NHibernate with RIA.NET' article :)

Thanks!

Gravatar

I ran into the same problem. When I query a derrived type with a navigation property I get an error: "Navigation Properties are not supported on derived entity types". I believe this is fixed in ADO.NET Data Services 1.5 CTP2, so I added references to those DLL's. Now my code doesn't compile:

The type 'System.Data.Services.IExpandProvider' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data.Services, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

Not sure what's going on here but seems NHibernate is still looking for the DLL's from VS 2008 SP1.

-Nick


 



 
Save Cancel