SharePoint Data Access Layer Part II

Generics

In part one I talked about strongly typed access to SharePoint list items and we did set a base for how to retrieve values in a more strongly typed fashion. In part two I'll extend this example and show you how to retrieve wrapped items from a SharePoint list.

The solution

Our final solution is created out of three classes which all have a specific use.

  • Extensions class;
  • ListItemWrapper class:
  • ListWrapper class

The Extensions class is a static class which contains extension methods for SPItem, SPListItem and SPListItemCollection. These extension methods help us throughout our SharePoint development and can be extended to contain even more helpfull methods.

The ListItemWrapper class is an abstract base class that all of our custom wrappers should inherit. It provides us with the possibility to access properties of list items in a strongly typed fashion

The ListWrapper class is a generic class that helps us in querying sharepoint lists. Returning wrapped list items.

Sample code

If you're not interested in large chunkes of code you can find a download link with the full sourcecode and the end of this post. So be my guest and download it. If you however would like to get a feel of how you can use this simple class library hang on with me and I'll show you how to use it with a real life example.

Outline: We have a SharePoint site for a car selling business. On this site we have a SharePoint list with content types and one of those content types is the Car type. This Car content type has an id of '0x01000D483DA73079A341828E6E216045019A0078881191FD5D1642839403A59FC701C0' and several columns of which we take 3 columns for our example. It has an Url column that contains the website url of the brand named 'ManufacturerUrl'. It has an Integer column that contains the mileage named 'Mileage'. And it contains a LookupMulti column that contains a list of accessoiries named 'Accessoiries'

ItemWrapper

The only way we could normally access these fields in our code is by the field indexer on SPListItem. Which causes a lot of problems.

  • I'd have the names of these fields scattered all over my code;
  • I'd have to remember which types these fields contain and cast them every time;
  • I'd have to check the content type:
  • I'd have to check for null values

And that's just to name a few. That's why we create a wrapper. And our wrapper will take care of all of thos issues mentioned before. Just have a look at the next code.

public sealed class CarWrapper : ListItemWrapper {

        private static readonly string contentTypedId = "0x01000D483DA73079A341828E6E216045019A0078881191FD5D1642839403A59FC701C0";

 

        public CarWrapper(SPListItem listItem)

            : base(listItem, true, ContentTypeId) {

        }

 

        public static string ContentTypeId {

            get {

                return contentTypedId;

            }

        }

 

        public int Mileage {

            get {

                return ListItem.GetValue<int>("Mileage", 0);

            }

        }

 

        public SPFieldUrlValue ManufacturerUrl {

            get {

                return ListItem.GetUrlFieldValue("ManufacturerUrl");

            }

        }

 

        public SPFieldLookupValueCollection Accessoiries {

            get {

                return ListItem.GetLookupFieldValueCollection("Accessoiries");

            }

        }

 

        public static IEnumerable<CarWrapper> GetItemsByContentTypeId(string url) {

            return new ListWrapper<CarWrapper>(url).GetItemsByContentTypeId(ContentTypeId);

        }

 

        public static IEnumerable<CarWrapper> GetItemsByContentTypeId(SPList list) {

            return new ListWrapper<CarWrapper>(list).GetItemsByContentTypeId(ContentTypeId);

        }

    }

What you see here is a simple class that inherits from ListItemWrapper. We set the ContentTypeId to the Id of the Car content type and we add our three columns as properties. To retrieve the values in our properties we simply use the extension methods from our library. So from now on we can actualy access our properties strongly typed, without knowing exactly what field the value comes from. Just like this:

CarWrapper someCar = new CarWrapper(someSPListItem);

 

Console.WriteLine(someCar.Mileage + " miles");

Console.WriteLine("Accessoiries:");

foreach (var accessory in someCar.Accessoiries) {

    Console.WriteLine(accessory.LookupId + " : " + accessory.LookupValue);

}

You must admit that this does look a lot better already don't you? This alows for much faster development. Do not forget the intellisense you get when you're working with strongly typed code and the fact that there's an automated check to validate the content type id(which is optional). So we do have a wrapper but we are not finished yet. Why not automagically wrap all list items of a list? It's very very easy beacause of the generic ListWrapper class.

ListWrapper

Most of the time we would like to itterate through a number of list items in a SharePoint list. And if possible in a strongly typed fashion right? Well if you did take a good look at the wrapper class you would have noticed that there are two methods in there that return an IEnumerable of type CarWrapper simply by the Url or an instance of a SPList. I used the generic ListWrapper class to do so.

Imagine you have just one list in you site where you store all the cars. You could extend the wrapper with static methods that return IEnumerables of CarWrapper without the input of a url. Have a look at this:

private static readonly string carUrl = "http://mysite/lists/cars";

 

public static IEnumerable<CarWrapper> GetAllCars() {

    return new ListWrapper<CarWrapper>(carUrl).GetItemsByContentTypeId(ContentTypeId);

}

Wrap it up

I would like to point out is that this library is not your end point. You can extend your wrappers to allow for updating or add a lot of predefined queries. All I realy want you guys and girls to do is work strongly typed! Because I don't know about you but I'm realy tired of reading lines like 'int mil = (int)item["Mileage"]' all over the code. We should not work like that do we?

Please do leave a comment if you do or do not like my idea of working with SharePoint list items.

Happy coding!

Wesley

2 Comments

  • Hi there, great post! Combine this with some abstract factory and some runtime class instantiation and you could build a nice wrapper around the "gooy" entrails of SharePoint and finally make it workable for us mere 'WinForms' mortals.

    Cheers, Baudin

  • @peppe: Nice idea never thought of it. But there's already the SharePoint bast practices kit that encourages the repository pattern. Maybe we should let the people stick to that in order to have one unified way we access SharePoint lists.

    If there are more out there who would like to make it a codeplex project, just leave a comment and I'll see what I can do.

    Cheers,
    Wes

Comments have been disabled for this content.