Pages

Monday 5 September 2011

Organizing Data in Lists

Every application needs a flexible data model as a foundation. The user needs somewhere to store, deal with, and retrieve data. The data represents the natural and virtual objects managed in the application. SharePoint organizes data in lists and their derivatives, the libraries. Several objects assist with defining the list’s structure, such as field types and content types.

Lists and Their Elements

Metadata is a semantically enhanced description of the data to express the meaning of data. For example, adding additional information (such as author, date, and keywords) to a document stored in a document library enhances the ability of a search engine to find it and order the results. SharePoint’s list model is amazingly flexible. Moreover, it empowers ordinary users to create and manage their own data store—normally a function “for experts only.” After years of computer technology advancement, the administration of a data model is no longer rocket science. However, this does not mean that you—as a developer—cannot programmatically interact with the data model. The whole power of the list model and its associated parts is available through the object model. Whatever the end user may do (and most of what they can’t do) through the UI, you can accomplish with the object model.

Early on in your contact with SharePoint lists, you should have encountered the term content type. Though they are ignored by many, they are, as a matter of fact, a core concept.

CONTENT TYPE DEFINITION

A content type is a reusable collection of settings you want to apply to a certain category of content. Content types enable you to manage the metadata and behaviors of a document or item type in a centralized, reusable way.

Creating a List Programmatically

You can easily create a new list using the Add method of the SPListCollection type. The code shown next demonstrates this in a console application.

using (SPSite site = new SPSite("http://sharepointserve"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = null;
string listName = "Books";
// Check whether the list already exists
try
{
list = web.Lists[listName];
}
catch (ArgumentException)
{
}
if (list == null)
{
Guid listId = web.Lists.Add(listName, "All our books",
SPListTemplateType.GenericList);
list = web.Lists[listId];
list.OnQuickLaunch = true;
list.Update();
}
Console.WriteLine("Created list {0} with id {1}", list.Title, list.ID);
}
}

This code runs in a console application and creates a new generic (custom) list without any additional columns. Before creating a new list, you should check whether it already exists. You can either loop through all lists or try to access the new list and catch the exception thrown if it doesn’t yet exist. An alternative approach is to use a LINQ query:

bool exists = (from l in web.Lists.OfType()
where l.Title.Equals(listName)
select l).Count() > 0;

The list itself is not queryable and must be copied into a List element using the OfType operator. That means the list is copied completely and uses a significant amount of memory if you have many lists. However, from the perspective of clean code, the pattern seems smarter than a try/catch block.

Adding Fields to the List

Once the list exists, you can add fields. Fields represent the columns. Internally, a field is a type derived from SPField. SharePoint includes a number of predefined fields for specific types. The following example demonstrates adding several fields for scalar types:

list.Fields.Add("ISBN", SPFieldType.Text, true);
list.Fields.Add("LeadAuthor", SPFieldType.Text, true);
list.Fields.Add("Price", SPFieldType.Currency, false);
list.Update();

The SPFieldType enumeration contains all possible types. You can also define custom types and extend the list of field types. A field type is not only a scalar or complex value; it can also have a relationship to a custom field editor.

Changing Field Properties

Certain properties are not available through the UI. Even SharePoint Designer, with its advanced capabilities, eventually reaches its limits. The example in the next Listing shows how to enable an invisible field to appear in the dialogs again and remove the read-only flag.

using (SPSite site = new SPSite("http://sharepointserve"))
{
using (SPWeb web = site.OpenWeb())
{
SPList questions = web.Lists["Questions"];
SPField field = questions.Fields["Voters"];
field.Hidden = false;
field.ReadOnlyField = false;
field.Update();
}
}

The change affects only the SPField object—not the list. The code snippet assumes you have a Questions list with a Voters field that is hidden and read-only. The changes are assigned to the underlying content type if the column is defined there. There is no need to change the particular content type directly.

Adding Items to the List

Adding items is as straightforward as adding fields. However, the procedure is not yet type-safe because the column’s ID must be provided as a string or Guid. The field name you need to use here is the internal Name, not the DisplayName.

Using a string that clearly describes the field is recommended:

SPListItem item = list.Items.Add();
item["Title"] = "ASP.NET Extensibility";
item["ISBN"] = "978-1-4305-1983-5";
item["LeadAuthor"] = "Joerg Krause";
item["Price"] = 59.99;
item.Update();

An ArgumentException is thrown if a field name does not exist. Alternatively, you can use the field’s zero-based index or its Guid to identify the field. This is recommended if the index or Guid is returned from any previous operation, to avoid errors due to mistyping.

Working with Attachments

Each item in a SharePoint list has an associated SPAttachmentCollection array. The collection contains strings, which may seem odd, as you would expect SPFile objects instead. What you see is a direct representation of the underlying storage model. Attachments are part of the containing web. This means that all lists share all their attachments in one library. The names collection must be combined with the web’s URL to give the complete address to the file in the repository.

Fortunately, the SPAttachmentCollection has several useful direct methods, such as Add, Delete, and Recycle.

SPList list = web.Lists["MyList"];
foreach (string fileName in item.Attachments)
{
SPFile file = item.ParentList.ParentWeb.GetFile(
item.Attachments.UrlPrefix + fileName);
// Work with SPFile
}

Another usage scenario could look like this:

using (SPSite site = new SPSite("http://sharepointserve"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["WordDocuments"];
SPListItem item = list.Items[id];
if (item.Attachments.Count > 0)
{
SPFile attachment = item.ParentList.ParentWeb.GetFile(
item.Attachments.UrlPrefix + item.Attachments[0]);
Stream content = attachment.OpenBinaryStream();
using (Package p = Package.Open(content))
{
// handle as a package (just a suggestion)
}
}
}
}

This code assumes that you have a list, called WordDocuments. The current item is selected by using the variable id. The code checks whether one or more attachments are present, and if so, it reads the first attachment (index zero). The attachment is loaded into an SPFile object and read as a binary stream. We suggest you use the Package class to access files in the package format (such as XPS, DOCX, XSLX, and so forth). The Package class is defined in the namespace System.IO.Packaging—the containing assembly is WindowsBase.dll.

No comments:

Post a Comment

Popular Posts