Rants Tagged with “nHibernate”

1  2  >  >>  (Total Pages: 2/Total Results: 11)

New Silverlight 2 ADO.NET Data Service Example

Silverlight Logo

I've finally had a chance to update my Silverlight 2-ADO.NET Data Services example. In this new sample I show how to create a Line-of-Business application (an XBox Game editor) using ADO.NET Data Services against both an Entity Framework model and NHibernate. Unlike earlier examples, this one includes implementation against the ADO.NET Data Service Silverlight 2 library to support saving of changed entities. In addition, I show some techniques for paging, retrieving simple types over an ADO.NET Data Service and full styling of the application. I hope to add support for Forms Authentication in the coming weeks.

Feel free to post replies with questions about the sample.

Update on NHibernate 2.0 and LINQ

Silverlight Logo

It seems that because of some internal NHibernate changes that are required to make NHibernate LINQ work really well, the current version of NHibernate LINQ will not be supported.  Evidently there are a number of complex queries that do not work correctly under the current codebase. Its been announced that these changes will be made in the NHibernate 2.1 (which is in development). Follow the link to read the full details!

The Fable of the Perfect ORM

Silverlight Logo

Data is a funny business. While at the moment I am spending a lot of time teaching Silverlight, my passion still lives in the data. I was brought up on  Minisystems (Multi-user CP/M and the like) where you were dealing with something like a database (though we didn't have that as firm a concept as you might think). Later I did quite a lot of desktop database development starting with dBase II (yes, I am that old), Paradox, Clipper, FoxPro and even Access. That naturally led to client-server and N-Tier development. Throughout all the time its become exceptionally clear how much data matters to most applications.

But using databases can be difficult as there is an impedance mismatch with object-oriented development and the natural structure of data. The solution to this for many organizations has been to build data access and business object layers around the data.  These layers were meant to simplify data access for most developers and embed the business logic directly into a re-usable set of code instead of it ending up in the UI layer. This was a good thing...

But the problem is that much of the data access (and to a lesser extent, business object) code was very redundant. Developers ended up writing the same code or simply mimicking schema that was in the database. Some started to develop ways to use the database schema to their advantage to limit the amount of hand-written code was created. While not always called this, this is where object-relational mapping (ORM) products got their start. 

ORM is a good thing.  But ORM is about data access, not business rules. Its a important distinction that needs to be understood.  ORM's typically were bad at defining and managing business rules, but that was never their job. Keep this in mind when you think about ORM and Business Objects (or just read Rocky Lhotka's book on the subject).

Now that ORM's have become a staple of data access, we have a ecosystem where there are a huge number of competing products (1st party, 3rd party and open source). The most common question I get these days when I meet people at user groups or conferences is "What ORM should I use for my new project?" This question is flawed. The problem with this question is that there is not a singular solution for data access (ORM et al.) that solve all problems. In fact there are many solutions to this problem that fit the needs to particular use cases. So when I get this question, I attempt to ask more questions but in reality this isn't a question that can be answered on the back of a napkin.

The recent brouhaha about the Entity Framework is a great example of this problem. Many of the complaints about the Entity Framework (or any ORM really) are central to the viewer's point of view. This is true of NHibernate as well. Its great in the right environment, but lousy in others. I wish I could encourage the community to stop trying to find the perfect ORM.  It doesn't exist. Its like the perfect car, perfect beer or perfect woman. The perfect car for speeding on a racetrack is horrible for taking the kids to hockey practice.

Why do I think this is true? Because I tried to write it. Several years ago I was fed up with the ORM landscape and decided that I would try to write one that fixed the flaws of all the other solutions. I spent nearly four months part time tinkering with the code to get it working the way I wanted it to.  But I kept finding myself backed into corners.  "If I implement it this way, its great for X, but lousy for Y." I finally decided that all ORM's are flawed because the problem is inherently driven by a core set of requirements.  No tool could possibly meet the criteria of every project.

Picking a data access strategy involves more than just functional requirements. Its not about the size of the project, the speed of the runtime environment or even the veracity of the tools. Its bigger than that. Though this list is incomplete, when I talk to people about this problem I encourage them to look at the requirements of their project to include (but not limited to):

  • Functional Requirements
  • System Requirements
  • Skill-set of the Development Team
  • Business Factors
  • Time-to-Market
  • Business Culture
  • Lifetime of Project
  • Volatility of Schema

I could go on, but I think you can fill this out with lots more. The situation is that ORM's that are good for certain environments are bad for others.  For example, if I were writing a website for a mom-n-pop Pizza Parlour in my neighborhood, if I had to have data, I'd likely pick something like "LINQ to SQL" as it is always going to be directly mapped to tables and the size of their database and throughput are low.  Getting the job done on budget is more important than worrying about performance or refactor-ability.

In contrast, if I was building a large financial system where concurrent transactions and high volume processing was critical to the project's success, I'd likely hand-code or use something like NHibernate.  Spending more time on hand coding for performance pays off on a big, high-volume project like this but would be wasted on the other project.

Lastly, if I were to be remotely working on a small project with a team who are not that well versed in database development, I might pick something that did a lot of the code generation for me (like LLBLGenPro) where the developers could get up to speed quickly without having to understand the basics of database development.

Some times its specific philosophies that help find the right match. For example, if persistence ignorance and implicit data loading is important to your team, then a technology like NHibernate makes a lot of sense. But NHibernate often comes with the higher cost of object tracking (e.g. often you'll consume 2x memory with NHibernate since they are keeping the old and new objects to do comparisons).

Other example is the difference in philosophy of data access. One of the driving ideas in Entity Framework is the idea that a developer should never make a request to the database the they don't know about. This is very different from the idea in NHibernate that requesting a related object should *just work*. That's why understanding your team, your culture and your project all come together to help you find the right solution.

Please don't take my mentioning of specific technologies as specific preference but instead understand that picking a tool requires more than trivial review (e.g. (Its included in Visual Studio for free so we should use it.")  Ultimately most projects spend more time tuning and tweaking their data access than building it so picking the right tool that gives you enough control is key to success.  Don't get blinded by shiny designers, its ultimately the code that is more important. 

I welcome your experiences and opinions...

Implementing IUpdatable (Part 3)

Silverlight Logo

UPDATE: I know the title is wrong and it should be IUpdateable but I didn't want to break any links for any RSS feeds that already had it.

If you haven't read Part 1 or Part 2 first, you should start there.

In this final part of the IUpdateable implementation, we will discuss the rest of the methods which includes ClearChanges, ResolveResource, ReplaceResource, SetReference, AddReferenceToCollectionRemoveReferenceFromCollection and SaveChanges.

ClearChanges is a simple method that simple undo's any changes that have accumulated.  In my implementation, I simply clear the UpdateCache that we discussed in Part 2 as well as clear the NHibernate Session to undo any changed that were previously saved (but not persisted to the database).

ResolveResource is a funny little method. In the implementation documentation for the IUpdateable interface, they specify that in most cases you can return a token or anything you want that uniquely identifies an item instead of an actual object reference. For example, when you implement CreateResource the return value can be the actual resource or can be some token that you know how to resolve to the resource.  This method is the one that will turn that token into an object reference if you've used that functionality. In our case we're actually returning object references so this becomes a non-issue and we just return the object that is passed in.

Next up is ReplaceResource. Not surprising, this method is used to complete replace a resource with another copy (who may have the correct values already set). The first parameter is a query who must return a single object.  For my implementation, I first retrieve the single instance from the query and then walk through the properties to set the new values. Simple really.

The next couple of methods have to do with relationships between objects. The SetReference method takes three parameters: the target resource, the property name and the property value.  The property value is an object who needs to be assigned to a property of the target.  The property name to be assigned in the 2nd parameter.  The implementation is pretty simple: I used the existing SetValue implementation to set the correct property with the correct value.

The AddReferenceToCollection and RemoveReferenceFromCollection are related methods.  One adds an object to a collection and one removes it from the collection. Both of these methods take the same signature that SetReference uses (target, property name, property value). The difference here is instead of setting the reference, you need to add or remove it from a property (which is the collection). For my AddReferenceToCollection implementation, I use reflection to find an "Add" method and invoke it with the new reference. For the RemoveReferenceFromCollection, I do the same but I am looking for a "Remove" method to invoke. Using reflection in this way does not require that the collections follow any specific pattern but do require an Add and Remove method. I chose this implementation because I was copying ADO.NET Data Services' implementation that they use for the Entity Framework. I could have expected IList since that is the standard way that NHibernate usually implements collections, but I decided to use this implementation first and if I had to refactor it I would.

The last method to implement is SaveChanges. This method is pretty straightforward as all pending changes that the IUpdateable interface has applied should be applied during this call.  IUpdateable expects that SaveChanges will be atomic (e.g. pass/fail, no partial updates).  To enforce that requirement, I used the NHibernate Session object's BeginTransaction method to start a transaction so that I could rollback any changes that failed. Because I had kept a cache of updates so I could clear them if necessary, I walked through them once the transaction had began and applied them to the Session object.  Finally I flushed the session to force the persistence to happen and ended the transaction. I did this all in a try...catch block so I could rollback the changes if any exceptions were thrown. SaveChanges does not have a return value so if it fails you are expected to return a DataServiceException. So in my catch block, after rolling back the transaction, I throw a DataServiceException and pass along the caught exception as the inner exception.

Overall the implementation was pretty simple. I hope that these articles will help anyone who is trying to implement this for their own data that they want to use in ADO.NET Data Services.

 

Implementing IExpandProvider for NHibernate.LINQ

Silverlight Logo

NOTE: This blog post is an adjunct topic to the IUpdateable series of posts that I have here and here.

As part of my work on the ADO.NET Data Services support for NHibernate.LINQ I decided that we should support IExpandProvider as well. 

For the uninitiated, IExpandProvider is another interface that ADO.NET Data Services support to allow the expansion feature of Data Services to work.  Essentially, expansion is about eager loading of related entities as part of a Data Service Query.  For example, if you had a Data Services query that said:

http://www.silverlightdata.com/simple/HibProducts.svc/Products(1)

This URI would go retrieve the Product, but if you wanted to retrieve the Category (a related entity) as part of the single call, you could annotate the URI with a query string parameter called $expand to indicate the paths to eager load:

http://www.silverlightdata.com/simple/HibProducts.svc/Products(1)?$expand=Category

In fact, the expansion support allows you to specify multiple paths (separated by commas) to eager load:

http://www.silverlightdata.com/simple/HibProducts.svc/Products(1)?$expand=Category,Supplier

The way it works inside the Data Service is that checks to see if the context object specified in the Data Service support IExpandProvider (the built-in Entity Framework provider does this automatically).  If it supports the interface, it calls the ApplyExpansions method.  At that point, the provider is supposed to take the IQueryable interface and change the query to support the expansions.  Remember, the methodology of Data Services is to take the URI syntax and convert the query into an IQueryable instance.  At the end of the process it executes this query so the IExpandProvider happens before the database is ever involved. All it needs to do is to expand the expression tree to add the expressions necessary to expand the nodes.

So how did I go about it?  My first step was to add expansion support to the LINQ interface.  Before I got started, eager loading was the responsibility of the user of the LINQ query. There was no way to make eager loading happen in the expression tree.  I modeled the support after the way that Entity Framework supports eager loading and added a new expression (called Expand in the NHibernate.LINQ provider) that instructs the underlying provider to eager load a certain path. Interestingly the ICriteria support in NHibernate already had support for eager loading so it was more plumbing to the NHibernate functionality that any real work. The expand works during the data source of the LINQ query:

var query = from timesheet in session.Linq<Timesheet>().Expand("Entries")
            where timesheet.Entries.Count > 0
            select timesheet;

By adding the Expand method call, it adds a hint to the query to eager load the Entries on the Timesheet object. Now that expansion is supported in the LINQ provider, I can wire up the IExpandProvider to simply add that expression for every path.

To support it, I simple walk through each of the paths that are passed to the ApplyExpansions method, but its not quite that simple. The method signature is:

IEnumerable ApplyExpansions(IQueryable queryable, 
                            ICollection<ExpandSegmentCollection> expandPaths);

The first property is the query that you are going to modify for the expansions. The second parameter is a list of ExpansionSegmentCollections.  Yup, a collection of a collection. I am unclear why this is so, but nevertheless, I simply go through each collection of collections (I've never been passed more than one, but perhaps MS can explain why).  The ExpandSegmentCollection is a collection of ExpandSegment objects.  This object supports two pieces of information: Name and Filter. Name is the path that is requested in the URI syntax; and Filter which it is unclear the exact use case.  In my implementation, I simply threw an error if I found a filter since I couldn't find any code path that caused them so I didn't know how to modify the query to support them.  My guess is that its there for future use.

So there you go, its added.  This new interface in coordination with the IUpdateable makes any NHibernate object supported in not only LINQ but also ADO.NET Data Services.  What do you think?

Speaking at the Atlanta .NET Users Group

Silverlight Logo

Next Monday night (July 28th, 2008), i'll be giving the short Q&A session at the Atlanta .NET Users Group.  The topic?  NHibernate's LINQ and ADO.NET Data Services support.  If you're interested in using NHibernate but don't want to give up your LINQ skills, stop by for a listen!

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.

Silverlight 2 + NHibernate.LINQ == Sweet

Silverlight Logo

UPDATE: Looks like I uncovered a ADO.NET Data Services bug in FF3.  The examples will only work with IE and Safari at the moment.

After a couple of weeks on and off the project, I finally finished the first stab at adding ADO.NET Data Services support to NHibernate.LINQ. To accomplish this I've added three features:

  • Support for IUpdateable to support full NHibernate CRUD.
  • Support for a new Expand extension method to do eager loading via the LINQ interface.  (The Expand method is similar to Entity Framework's Include method.)
  • Finally, using the Expand extension method, I implemented the IExpandProvider interface to allow for expansions via the REST API.

These changes have been posted to the NHContrib project (where the NHibernate.LINQ lives) to allow the committers to validate and add it to new versions of the project. I am sure that it will need some refactoring and tweaking but the basics are done.

In addition, I'll be finishing up my discussion of implementing the IUpdateable interface pretty soon to help those of you adding this support to your projects. I'll also be blogging about how I added the IExpandProvider to help those of you trying to add that to your projects (or even to LINQ to SQL).

To prove out this new support, I've launched a new version of my Simple ADO.NET Data Services project with a NHibernate flavor.  Go visit http://www.silverlightdata.com to see it working.  In addition, I updated that sample to include paging support to make it a little more performant.

Let me know what you think.

Implementing IUpdatable (Part 2)

Silverlight Logo

If you haven't read Part 1 yet, you can read it here.

After spending time creating my own caches of reflection data I found the NHibernate type information to be more complete and faster. Go figure.  At this point I am using the SessionFactory's GetClassMetadata and GetCollectionMetadata to return IClassMetadata and ICollectionMetadata interfaces. So far this has given me every piece of runtime information I need and means that I don't need to do any nasty (and potentially fragile) walking through the property interface of the context object. Whew...

So to refactor my GetResource and CreateResource calls. GetResource is easy.  GetResource passes in the query and the full type name (though the full type name may be missing in some cases). The query it passes it must resolve to a single result.  That means I can simply execute the the query and if it returns more or less than one result, return an error.  Once I have the result I can just check it against the full type name (if it was passed in) and return the value.

CreateResource is a bit more complicated. The IClassMetadata allows me to call their Instantiate method to create a new instance of the class but the new instance is not initialized with any data.  Most notably, the missing detail is a key. In the case of many entities, this is fine (e.g. if zero ID is a valid "new" entity).  But in others the key needs to be specified. (Customer in the Northwind database is an example of this.) The problem is that we have to keep a reference to the new objects so that when ADO.NET Data Services asks us to set properties, get properties and save, we have to have the object in the Session.  But we can't add it to the Session with an invalid key.  What to do?  My solution for now is a local cache of objects that are not ready to be saved (only really happens with newly created objects). When we are ready to save, we'll just add it to the Session then (when its either valid or we'll throw an exception because its invalid).

Now a quick mention of GetProperty and SetProperty. These are both pretty easy as the IClassMetadata includes a similar method to set and get properties. The only wrinkle is that if you try and set a key using the GetProperty/SetProperty, the keys are not in the list of properties.  Because of this I just checked to see if the property is part of the key and set the key instead, if its not part of the key we can just set or get the property.  Now that we have the basic part of the interface complete  its down to the hard parts.   But that's for the next part!

 

Implementing IUpdatable (Part 1)

Silverlight Logo

I have been diving pretty deep into ADO.NET Data Services (see an upcoming article about ADO.NET Data Services and Silverlight 2 coming soon). I've been looking at the story around non-Entity Framework models through a Data Service and thought that NHibernate through a Data Service would be a great example.

So I tried to get it to work with the NHibernate LINQ project. The example model that the project uses is a simple Northwind model. I thought I'd just take that model and expose it via ADO.NET Data Services. I crufted up a simple Data Context object for ADO.NET Data Model but it didn't work. ADO.NET Data Services was complaining about the fact that the end-points (e.g. IQueryable<Customer>) was pointing at an Entity. This was a bug...a but in ADO.NET Data Services.  I hacked together a fix to get around it (and reporting it).  If you're interest, the problem is that if the key of the entity is in a base class and *not* named "ID", it fails to find it.  Again, this is a bug not a feature of ADO.NET Data Services.

Now that it was working, now what? I wanted to be able to make changes to the model but the NHibernate context doesn't support the updating interface: IUpdatable.  (Though I sure wish they'd rename it IUpdateProvider to match the IExpandProvider interface). If you're not familiar with this requirement, note that only the Entity Framework currently support the IUpdatable interface (and is in fact implemented inside of ADO.NET Data Services not directly in Entity Framework).  This means that DataSets and LINQ to SQL do not support it either. 

That's where I went to the Rhino Google Group (the discussion point for this project) and offered to implement the IUpdatable for the NHibernate provider. I thought it would be a fun exercise to understand the guts of the ADO.NET Data Service stack.

My first chore was to attempt to find a solution to decouple System.Data.Services.dll from the rest of the LINQ provider. My reasoning for this is that ADO.NET Data Services requires .NET 3.5 SP1 and I didn't want to tie the changes to that version of the Framework. Interestingly this is the same tactic that the ADO.NET Data Services team took.  This is why the Entity Framework does not implement the IUpdatable interface themselves, but the ADO.NET Data Service does it for them.  For the rest of the world, it expects a IUpdatable implementation directly on the context object that is used as the starting point for the service. After running around a number of ideas and running it by the Rhino people, we've decided to table that problem and get the interface working.  That will be a fight we fight later with a number of proposed solutions.

So now that architecture is out of the way, its time to start actually implementing the interface.  For the first pass, I am going to implement IUpdatable directly on NHibernateContext and refactor it later for less tight coupling. While I am at it, I also want to add support for IExpandProvider so that we can do expansions through NHibernate.

After adding the interface to the context object, I looked through the interface (its about a dozen calls that need to be implemented) to determine where to start. I am starting with the simple calls (GetResource, CreateResource, DeleteResource).  These calls are used by the service to do basic object manipulation.

For GetResource, I am handed a query and possibly a type name. GetResource is supposed to invoke the query to get the one and only one result (implementors should throw an error if the result returns more than one result) and then check the type name against the result.  In some cases you won't get the type name, but in most cases you will need to verify that the type of the result is the same as the type name. This is used to make sure that derived types are correctly retrieved from the data provider.

In implementing CreateResource, I noticed that I needed to be able to look up type information. Type information is important as I need information about the containers (e.g. IQueryable endpoints) on the context object.  This information is not readily available as its the classes that derive from NHibernate that add these end-points. I could get the type information via NHibernate's type information or using Reflection (neither are particularly cheap). For the first iteration I choose Reflection since I know that better, but I wanted to mitigate the cost with some caching. To that end, I've created some small in-memory caches of the reflection information that hopefully will help with the performance of these lookups.  This type information will help act like a factory to create new instances of the object. Unlike other ORM's, NHibernate doesn't use factories but uses simple object creation so we can just use the reflection information to create the instance of the new object and attach it to the NHibernate ISession.

Lastly, the simplest of the three methods to implement is the DeleteResource as it passes in a query (again, should always only return a single result) and mark it deleted in the session.  The change shouldn't be persisted (there is a SaveChanges call on the IQueryable interface that facilities the actual persistence to the data store).

Overall a fun couple of days.  Now on to the rest of the interface.  I'll keep you posted with my experience dealing with them!