NHibernate 101: Silverlight 4 with NHibernate 2.n

clock February 1, 2010 05:44 by author jamesstill

In this intro I'll create a vanilla Silverlight 4 application, hosted in a WCF Service, and wired up to SQL Server 2008 with the open source NHibernate ORM tool. I'm not going to dive into the weeds here. I just want to show the basics.

Prerequisites:

* Visual Studio 2010 Beta 2
* Silverlight 4 Tools for VS 2010
* NHibernate 2.n
* SQL Server 2008

In Visual Studio create a new project using the Silverlight Application project template. When prompted, choose to host the project in a new web site with the default ASP.NET Web Application Project type. I'll call it "ConcertMusic.Web" because we're going to fetch a list of classical music instruments from a database table and display them in a SL DataGrid. Do not enable .NET RIA Services.

After the project template unfolds right-click the ConcertMusic.Web and create a WCF Service using the Silverlight-enabled WCF Service template. I'm not going to get into WCF here but you'll want to create a contract interface, configure the service behavior and bindings, and perhaps add a ClientAccessPolicy.xml file. Here's my service contract:

   1:  namespace ConcertMusic.Web
   2:  {
   3:      [ServiceContract(Namespace="http://ConcertMusic.Web/2010/07")]
   4:      public interface IConcertMusicService
   5:      {
   6:          [OperationContract]
   7:          IList<Instrument> GetInstruments();
   8:      }
   9:  }

Now let's configure NHiberate. Add references to the required NHibernate assemblies: NHibernate.dll, log4net.dll, Iesi.collections.dll, and Antlr3.Runtime.dll. (Optionally, include Castle or Spring assemblies if you want to support lazy loading. I'm not going to get into that here.)

In Web.config add the plumbing to configure NHibernate:

   1:  <configuration>
   2:   
   3:    <configSections>
   4:      <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
   5:    </configSections>
   6:   
   7:    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
   8:      <session-factory>
   9:        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
  10:        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
  11:        <property name="connection.connection_string">Data Source=SERVER_INSTANCE;Initial Catalog=DatabaseName;Integrated Security=SSPI</property>
  12:        <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
  13:        <property name="show_sql">false</property>
  14:        <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
  15:      </session-factory>
  16:    </hibernate-configuration>

Ok so we've got the NHibernate assemblies referenced and we've configured it the project. Let's start at the database and work our way forward. First, we've got a table of musical instruments in the database:

   1:  CREATE TABLE [dbo].[Instrument](
   2:      [ID] [int] IDENTITY(1,1) NOT NULL,
   3:      [Name] [nvarchar](50) NULL,
   4:      [Description] [nvarchar](120) NULL,
   5:   CONSTRAINT [PK_Instrument] PRIMARY KEY CLUSTERED 
   6:  (
   7:      [ID] ASC
   8:  )WITH 
   9:  (PAD_INDEX  = OFF, 
  10:  STATISTICS_NORECOMPUTE  = OFF, 
  11:  IGNORE_DUP_KEY = OFF, 
  12:  ALLOW_ROW_LOCKS  = ON, 
  13:  ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  14:  ) ON [PRIMARY]
  15:   
  16:  GO

We need to do two things to map the table to a plain old CLR object (POCO) in our application. We have to create the POCO class and then we have to create a mappping file that tells NHibernate how to create an instance of that class from the data store. Here's our simple POCO class:

   1:  [DataContract]
   2:  public class Instrument
   3:  {
   4:      public Instrument() { }
   5:   
   6:      [DataMember]
   7:      public virtual int ID { get; set; }
   8:   
   9:      [DataMember]
  10:      public virtual string Name { get; set; }
  11:   
  12:      [DataMember]
  13:      public virtual string Description { get; set; }
  14:  }

Notice that we're using auto-implemented properties introduced in C# 3.0. Also, the class is implemented as a DataContract with DataMember properties. This is necessary if you want to bind an IList collection of Instrument objects to a Silverlight control. If you don't use DataMember attributes, then Silverlight will attempt to bind to the IL-generated backing fields instead and you'll get skinny blank rows in your DataGrid.

Ok, now let's create the NHibernate mapping file. It can live in the same place as the POCO or you can put your mapping files in a separate folder to keep them all together. It's up to you. The naming convention is [ClassName].hbm.xml:

   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <hibernate-mapping assembly="ConcertMusic.Web" xmlns="urn:nhibernate-mapping-2.2">
   3:    <class name="ConcertMusic.DomainModel.Instrument, ConcertMusic.DomainModel" table="Instrument" lazy="false" >
   4:      <id name="ID" type="Int32" column="ID">
   5:        <generator class="identity" />
   6:      </id>
   7:      <property name="Name" column="Name" />
   8:      <property name="Description" column="Description" />
   9:    </class>
  10:  </hibernate-mapping>

I'm not going into a long explanation of this file. Read the NHibernate docs for a detailed specification. For now I'll just say that ID is described as a synthetic key (identity column), and Name and Description are mapped one-to-one to identical column names in the table. Pretty straightforward. Very important! Change the build action of this xml file to make it an embedded resource. It needs to be compiled into the assembly in order by NHibernate to find it at runtime.

NHibernate uses an ISessionFactory to talk to the database. Just like IDbConnections in ADO.NET, these are very expensive to set up so you don't want to set them up and tear them down with every transaction to the database. The best practice is to create them once and then hold onto them during the lifetime of the application. Here I'm using a Singleton pattern to wrap the factory in a helper class:

   1:  public class NHibernateHelper
   2:  {
   3:      public static readonly ISessionFactory SessionFactory;
   4:   
   5:      static NHibernateHelper()
   6:      {
   7:          Configuration cfg = new Configuration().AddAssembly("ConcertMusic.DomainModel");
   8:          SessionFactory = cfg.Configure().BuildSessionFactory();
   9:      }
  10:   
  11:      public static ISession OpenSession()
  12:      {
  13:          return SessionFactory.OpenSession();
  14:      }
  15:  }

In line 7 I'm adding the assembly ConcertMusic.DomainModel to the NHibernate configuration. This is to tell NHibernate where my [ClassName].hbm.xml mapping files live. I created a separate project for my POCO classes and NHibernate mapping files. Change this to Silverlight1.Web or whatever assembly name where your mapping files were added.

One last plumbing task to complete. We need to implement the OperationContract so that Silverlight can call and fetch a list of musical instruments. I keep my web methods very thin but for illustration purposes only I'll just code it right there:

   1:  public class ConcertMusicService : IConcertMusicService
   2:  {
   3:      public IList<Instrument> GetInstruments()
   4:      {
   5:          IList<Instrument> list;
   6:          using (ISession session = NHibernateHelper.OpenSession())
   7:          {
   8:              IQuery query = session.CreateQuery("FROM Instrument");
   9:              list = query.List<Instrument>();
  10:          }
  11:          return list;    
  12:      }
  13:  }

Do not do this in a production application. Get that data access plumbing out of your web method and into a data layer somewhere. That makes it easy to write unit tests that call the data layer too. But this is fine for our purposes. Run your unit tests and make sure it's all working. Then wire up the Silverlight MainPage.xaml to consume the data. Drag a DataGrid onto your MainPage.xaml. It should register the System.Windows.Controls.Data assembly and stub out a DataGrid for you:

   1:  <data:DataGrid x:Name="InstrumentDataGrid" AutoGenerateColumns="False" Height="400" Width="200">
   2:      <data:DataGrid.Columns>
   3:          <data:DataGridTextColumn Header="ID" Binding="{Binding ID}" />
   4:          <data:DataGridTextColumn Header="Name" Binding="{Binding Name}" />
   5:      </data:DataGrid.Columns>
   6:  </data:DataGrid>

Create a service reference to the WCF service in your Silverlight app. Then in the code behind make an async call to the web service and bind the results to the grid:

   1:  public partial class MainPage : UserControl
   2:  {
   3:      public MainPage()
   4:      {
   5:          InitializeComponent();
   6:          Loaded += new RoutedEventHandler(MainPage_Loaded);
   7:      }
   8:   
   9:      void MainPage_Loaded(object sender, RoutedEventArgs e)
  10:      {
  11:          ConcertMusicServiceClient service = new ConcertMusicServiceClient();
  12:          service.GetInstrumentsCompleted += 
  13:              new EventHandler<GetInstrumentsCompletedEventArgs>(Service_GetInstrumentsCompleted);
  14:          service.GetInstrumentsAsync();
  15:      }
  16:   
  17:      void Service_GetInstrumentsCompleted(object sender, GetInstrumentsCompletedEventArgs e)
  18:      {
  19:          InstrumentDataGrid.ItemsSource = e.Result;  
  20:      } 
  21:  }

That's all there is to it.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Brad Abrams on RIA Services with EF

clock November 19, 2009 06:26 by author jamesstill

Abrams basically walked through a typical RIA Services app and most of it is familiar to anyone who has studied the RIA Services documentation and walkthrough. However there were several new things specific to VS2010 and the new bits.

RIA Services is now built on top of WCF. Yep, it's a first-class citizen on the stack right next to Workflow Services and Data Services. Brad Abrams said his goal with RIA was to force n-tier dev and to get people into the 21st century. :) That's why (and I'm translating here, he didn't say this) RIA is a prescriptive framework following the 80/20 rule rather than something totally open ended like the vanilla ASP.NET web project template.

The project template is now out of the box in VS2010/.NET 4.0. Also, there's a design view for XAML now. In fact, all the SL controls are on the toolbox and you don't have to edit the XAML at all. My first impulse is one of repulsion -- however, I realize that this is a great time saver for doing a first cut on layout and wiring up controls. You can always go into the XAML and tweak it later.

with a DataGrid and Pager control RIA does not go grab all nn number of rows from the database and bind it to the grid like in early ASP.NET. It takes advantage of LINQ and gets only the rows for the current page. That data is cached locally so if user clicks back arrow to go back to page 1 it's there.

No more XAML exploring. VS2010 has a Document Outline toolbar that shows a visual representation
of the nodes and their hierarchy.

No more rebuilding the RIA Service in order to push the gs file down to the SL client. Changes are reflected right away.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


VS2010 and MS Deploy

clock November 19, 2009 06:21 by author jamesstill

VS2010 along with the existing project templates for SQL Server 2005/8 will now allow you to configure a complete build package that targets any environment as well as the database. Vishal Joshi did a demo at PDC that was pretty sweet. His blog is http://bit.ly/vijoshi and he has a lot of notes on known issues, release notes, and links to documentation. No longer will it be necessary to get the DBA and the sys admin to coordinate the push to staging or prod.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


About

SquareWidget LLC is an Oregon-based software development company that specializes in handcrafted .NET software solutions.

Search

Archive

Categories


Sign in