Getting started with NHibernate for SharePoint Part 4 – Working with a Links list

« Previous post (Show Lists and Libraries)


So far in this series we have been covering the absolute basics of getting started. We will continue to do so but dig in a bit more in how to work with some of the standard list templates in SharePoint. I will cover the following list templates in the following turorials

  • Links
  • Tasks
  • Announcements
  • Contacts
  • Calendar

Changes since last tutorial (Part 3)

Since we are stepping up a bit here and will introduce several new lists and more complexity I have moved around and refactored a bit in my project to create better separation. I did borrow some of the pattern from a normal MVC project

  • Business, contains business layers and core functionality
  • Content, where we will keep our NHibernate classes and mapping files
  • Models, where we will keep our operational methods for NHibernate

All and all the project now looks like this

Strategy to get started working with a new type of list

The first thing you must decide is which fields to work with. Detailed field information can be acquired by using a tool like SharePoint Manager or the Camelot .NET Connector with Mini SQL Query. I will use the Mini SQL Query in this guides since it will allow us to test some queries and have a really good overview of the fields and their data.

The Links list

If you have connected to a Team-site this list will already be there (as can be seen in the previous tutorial). If the list is missing simply create it using the SharePoint interface. Also add a couple of links here for us to test with.

Download Mini SQL Query and open it on the same computer / server as where you have Camelot .NET Connector installed. Run the query

SELECT * FROM Links.all WHERE ContentType = 'Link'

This should render a result looking like this

If you look around a bit on the result we will find that the following fields are out of interest,  ID, URLwMenu, Created, Modified, Comments. When running a query with those fields we will get a result looking something like this.

Simple enough, lets start to create some classes and mapping files

Content/Links.cs

This list seem simple but there is a small quirk in it. Note the format on the URL field (http://www.bendsoft.com, Bendsoft Website), one could think that the URL and Title should be stored in different fields but this is not the case, this is simply the way SharePoint stores URLs, this format is important to remember when inserting and updating data into URL fields in SharePoint.

We will ignore this small quirk for now but in the SDK this fields is replaced with a specialized URL property type that implements the IUserType interface.

Create the file Content/Links.cs and implement the following code

namespace NHibernateExample.Content
{
    public class Links
    {
        public virtual int ID { get; protected set; }
        public virtual string URL { get; set; }
        public virtual System.DateTime Created { get; protected set; }
        public virtual System.DateTime Modified { get; protected set; }
        public virtual string Comments { get; set; }
    }
}

Content/Links.hbm.xml

Create the file Content/Links.hbm.xml and enter the following mapping into it and remember to set the build action to “Embedded Resource”

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
  <class name="NHibernateExample.Content.Links, NHibernateExample" lazy="true" table="Links">
    <id name="ID">
      <generator class="native" />
    </id>
    <property name="URL" />
    <property name="Created" update="false" insert="false" generated="insert" />
    <property name="Modified" update="false" insert="false" generated="insert" />
    <property name="Comments" />
  </class>
</hibernate-mapping>

The Created and Modified fields are managed by SharePoint, hence we must prevent NHibernate from trying to write any data to such fields.

Models/Links.cs

In the MVC pattern you use Models when communication with your datasources and this is exactly what we do here as well. This is nothing else then a pattern in our scenario but it is recommended to separate classes and communication when doing ORM applications.

We will use this file for our CRUD (Create Read Update Delete) methods. Create the file Models/Links.cs and paste the following code into it

using NHibernate;
using System;
using System.Collections.Generic;
using System.Linq;

namespace NHibernateExample.Models
{
    /// <summary>
    /// The Model class of links
    /// Basic CRUD support is implemented
    /// </summary>
    public class Links
    {
        /// <summary>
        /// Get all data from the links list
        /// </summary>
        /// <param name="session"></param>
        public static void Read(ISession session)
        {
            IQuery query = session.CreateQuery("FROM Links");
            IList<Content.Links> results = query.List<Content.Links>();

            if (results.Any())
            {
                Console.WindowWidth = 90;
                const string header = "{0, -9} {1}";
                foreach (Content.Links item in results)
                {
                    Console.WriteLine(header, "ID", item.ID);
                    Console.WriteLine(header, "URL", item.URL);
                    Console.WriteLine(header, "Created", item.Created.ToShortDateString());
                    Console.WriteLine(header, "Modified", item.Modified.ToShortDateString());
                    Console.WriteLine(header, "Comments", item.Comments);
                    Console.WriteLine(new string('-', 20));
                }
            }
            else
            {
                Console.WriteLine("Could not fetch any lists");
            }
        }

        /// <summary>
        /// Get a single entry from the links list
        /// </summary>
        /// <param name="session"></param>
        /// <param name="itemId"></param>
        /// <returns></returns>
        public static Content.Links Read(ISession session, int itemId)
        {
            IQuery query = session.CreateQuery("FROM Links WHERE ID = :ID").SetParameter("ID", itemId);
            return query.UniqueResult<Content.Links>();
        }

        /// <summary>
        /// Insert new post in the links list
        /// </summary>
        /// <param name="session"></param>
        /// <param name="item"></param>
        /// <returns>The created object</returns>
        public static Content.Links Create(ISession session, Content.Links item)
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                var ret = session.Save(item);
                transaction.Commit();
            }
            Console.WriteLine("Saved link to SharePoint with ID {0}", item.ID);
            Console.WriteLine(new string('-', 20));

            return item;
        }

        /// <summary>
        /// Update a post in the links list
        /// </summary>
        /// <param name="session"></param>
        /// <param name="item"></param>
        /// <returns>The updated object</returns>
        public static Content.Links Update(ISession session, Content.Links item)
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Update(item);
                transaction.Commit();
            }
            Console.WriteLine("Updated link with ID {0}", item.ID);
            Console.WriteLine(new string('-', 20));

            return item;
        }

        public static void Delete(ISession session, Content.Links item)
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(item);
                transaction.Commit();
            }
            Console.WriteLine("Deleted link with ID {0}", item.ID);
            Console.WriteLine(new string('-', 20));
        }
    }
}

That’s pretty much all the coding we need to do. Lets test!

Testing

Use your Main method in the program.cs file and run the code

using (ISession session = SessionFactory.OpenSession())
{
    Models.Links.Read(session);
}


If you didn’t insert any data begin by doing so, the following snippet will insert a new link and read all available when done
using (ISession session = SessionFactory.OpenSession())
{
    Links link = new Links()
    {
        URL = "http://blog.bendsoft.com, Bendsoft Official Blog",
        Comments = "Attempt to insert data using NHibernate"
    };
                
    // Insert
    var newLink = Models.Links.Create(session, link);
                
    // Read
    Models.Links.Read(session);
}


How to use the other methods will speak for it self. Comment this post if this needs clarification!


« Previous post (Show Lists and Libraries)

This entry was posted in NHibernate for SharePoint, Tutorials and tagged , . Bookmark the permalink.

One Response to Getting started with NHibernate for SharePoint Part 4 – Working with a Links list

  1. Lelala says:

    Thanks for that comprehensive post. Have tackled this stuff for some hours, but you made it much easier :-)
    What i do not understand, is, why todays folks are not using the simple session-per-request pattern, instead everything is put into the CRUD DA-layer.
    Honestly, in nearly every web application i’ve seen, there are some situations in which you need “direct access” to a NH-SessionObject (yes, this may indicate a flaw in the design, but as apps get bigger, you will need some hacks at some points ;-) )

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>