Shane Jordan

SharePoint, .NET, Project Management and software development

I recently had a need to dynamically determine the names of both the Profile and Social databases in a SharePoint 2010 Farm.   Content databases names are easy, as they are part of each SPSite.  For example:

string ContentDBName = SPContext.Current.Site.ContentDatabase.Name;

In order to determine the names of the Social, Profile or other database names, you have to instantiate the SP Database Service and iterate through until you find the correct service or database type.  In this example, I loop through and then assign variables for the Social database and the Profile Database.  Each database will have a Name for its type such as “SocialDatabase”, “ContentDatabase” or “SocialDatabase”.


SPDatabaseService dbService = SPFarm.Local.Services.GetValue<SPDatabaseService>();

string SocialDBName = string.Empty;

string ProfileDBName = string.Empty;

// Enumerate the service instances
foreach (SPDatabaseServiceInstance instance in dbService.Instances)
{
// enumerate the databases within this service instance
foreach (SPDatabase database in instance.Databases)
{
if (database.GetType().Name == "SocialDatabase")
SocialDBName = database.Name;
else if (database.GetType().Name == "ProfileDatabase")
ProfileDBName = database.Name;
}
}

I’ve been working on some side applications and really wanted to build a generic Repository class in order to funnel all of my data access through.  The Repository pattern is explained very well by Ayende here:  http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/10/08/the-repository-pattern.aspx

At first, I created a separate Repository class for each and every entity that existed.  Each of these repositories had all of the basic CRUD operations, as well as any custom ones.  This led to many classes.

So if you had a Product, Customer and Address table in your database, that means you have a Product, Customer and Address Entity for each, then I would have a ProductRepository, CustomerRepository and AddressRepository class for each.  I wanted a more terse way to do this with less code.

After reading much of Entity Framework in Action (http://www.manning.com/mostarda/), there was a good pattern for a repository base, so I took that and expanded it for my purposes.

I created two intefaces IRepository and IUnitOfWork:

public interface IRepository<T> : ICollection<T> where T : class
{
IEnumerable<T> Query(Func<T, bool> predicate);
T GetSingle(Func<T, bool> predicate);
void Update(T Entity);
List<T> GetAll();
}

IUnitOfWork

public interface IUnitOfWork<T> where T : class
{
void SaveChanges();
}

And here is my Repository class

public class Repository<T> : IRepository<T>, IUnitOfWork<T> where T : class
{
private ObjectContext context;
private ObjectSet<T> entitySet;
private bool sharedContext = false;  // this just means it was not passed in

public Repository(bool ReadOnly)
{
ConstructorLoad(new SampleEntities(), ReadOnly);  // default the entitites, but allow for readonly override
}

public Repository()
{
ConstructorLoad(new SampleEntities(), true);  // default to read only entities
}

public Repository(ObjectContext context)
{
sharedContext = true;
ConstructorLoad(context, true);  // default to read only entities
}

public Repository(ObjectContext context, bool ReadOnly)
{
sharedContext = true;
ConstructorLoad(context, ReadOnly);
}

private void ConstructorLoad(ObjectContext context, bool ReadOnly)
{
if (context == null)
{
sharedContext = false;
context = new SampleEntities();
}

this.context = context;
this.entitySet = context.CreateObjectSet<T>();
if (ReadOnly)
this.entitySet.MergeOption = MergeOption.NoTracking;  // this will help add a lot of performance to calls, most are reads, no need for tracking
}

public IEnumerable<T> Query(Func<T, bool> predicate)
{
return this.entitySet.Where(predicate);
}

public List<T> GetAll()
{
return this.entitySet.ToList<T>();
}

public T GetSingle(Func<T, bool> predicate)
{
return this.Query(predicate).Single();
}

public void SaveChanges()
{
context.SaveChanges();
}

public void Add(T entity)
{
if (!this.Contains(entity))
this.entitySet.AddObject(entity);
}

public void Update(T entity)
{
if (!this.Contains(entity))
this.entitySet.Attach(entity);
}

public bool Remove(T entity)
{
if (!this.Contains(entity))
return false;

this.entitySet.DeleteObject(entity);

return true;
}

public bool Contains(T item)
{
ObjectStateEntry state;

if (!this.context.ObjectStateManager.TryGetObjectStateEntry(item, out state))
return false;

return (state.State != EntityState.Detached);
}

public void Clear()
{
}

public void CopyTo(T[] array, int arrayIndex)
{

}

public int Count
{
get
{
return 0;
}
}

public bool IsReadOnly
{
get { return false; }
}

public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}

IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}

~Repository()
{
if (!sharedContext && context != null)
{
context.Dispose();
context = null;
}
}

So now we have all of our generic CRUD items encapsulated within a generic Repository class.  In theory, I could switch my database and my ORM over to something else such as nHibernate, and would have very little impact to my codebase that uses this repository.

To use this repository to get one record by ID, I would call this:

Repository<Product> productRepo = new Repository<Product>();

Product product = productRepo.GetSingle(x => x.ProductId = 1);

I could also use it to get a list of all Products

List<Product> products = new Repository<Product>().GetAll();

Or I could save a new Product

Repository<Product> productRepo = new Repository<Product>(false);

Product product = new Product{

ItemName = “New Product”,

Price = 32.99,

Available = true

};

productRepo.Add(product);

productRepo.SaveChanges(product);

And finally to delete

Repository<Product> productRepo = new Repository<Product>(false);

productRepo.Remove(product);

productRepo.SaveChanges();

A couple of notes about the Repository

1. I’ve defaulted that the MergeOption is set to NoTracking by default, since the vast majority of my calls are reads, so I don’t need the tracking on.  This helps with performance, but can be a bit tricky if you forget to pass in a true variable to turn it on when you need to work with entities and save them.

if (ReadOnly)
this.entitySet.MergeOption = MergeOption.NoTracking;  // this will help add a lot of performance to calls, most are reads, no need for tracking

2.  ObjectContext is an expensive operation.  You can pass in the ObjectContext via the constructor or let it build one for you if just doing a single call.  It will Dispose of the context when the class terminates.

~Repository()
{
if (!sharedContext && context != null)
{
context.Dispose();
context = null;
}
}

Then I create a Service account for many of my related functionality and call the Repository from there.  For example the ProductService.  The services are not necessarily a one to one to the entities.  Less services.

I’m curious to see what everyone else is using for their Repositories.  I wasn’t able to find a ton of information on it out there on the Intertubes.

Cheers!

jQuery has become the defacto standard framework for client side programming  in all web programming camps (.NET, Ruby and Java).  One of the strong points of jQuery is it’s small, minimized core.  This core needs to remain small and one of the tradeoffs of this is no backwards compatible or legacy code support.  This actually a very good thing, as a small file size in the web world is paramount.  All that legacy code would bloat the core codebase causing slower downloads.  With each new version comes new breaking changes.

It is common to see plugins and code written against all three versions: 1.26, 1.32, 1.41

So what happens when you want to use the latest version, however, all of your plugins or UI frameworks only work with past versions?   What about that great little plugin that some guy wrote somewhere, but it only supports 1.2.6 and breaks with the latest version.

When a new version is released, your options would be to

A) Rewrite all plugins and codebase to support latest version (that’s a lot of work!)

B) Leave all your codebase on the older version (you would never be able to leverage latest stuff or newer plugins)

C) Maintain various versions of the jQuery framework

Let’s explore option C.   I removed my normal inclusion of the jquery framework on the Master page and created a View Helper to control this.

1. Create a new MVC 1 project in Visual Studio 2008

2.  Add a new folder called “Helpers”

3.  Add a new class called jQueryHelper

4. Paste in the following code.  I’ve also included logic to include CDN (Content Delivery Network) as well as options in enums for easier parameters

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace jQueryVersions.Helpers
{
    public class jQueryHelper
    {
        public static string jQueryCore()
        {
            return jQueryCore(jQueryVersion.v141, CDN.Google);
        }

        public static string jQueryCore(jQueryVersion ver, CDN cdn)
        {
            string version = "1.4.1";
            string path = "/Scripts/";                    

            switch(ver)
            {
                case jQueryVersion.v126:
                    version = "1.2.6";
                    break;
                case jQueryVersion.v132:
                    version = "1.3.2";
                    break;
            }

            switch (cdn)
            {
                case CDN.Google:
                    path = "http://ajax.googleapis.com/ajax/libs/jquery/" + version + "/jquery.min.js";
                    break;
                case CDN.Microsoft:
                    if(ver == jQueryVersion.v126)  // Microsoft doesn't appear to host a version 1.26
                        path = path + "jquery-" + version + ".min.js";
                    else
                        path = "http://ajax.microsoft.com/ajax/jquery/jquery-" + version + ".min.js"; ;
                    break;
                default:
                    path = path + "jquery-" + version + ".min.js";
                    break;
            }    

            return String.Format("", path);
        }
    }

    public enum jQueryVersion
    {
        v126,
        v132,
        v141
    }

    public enum CDN
    {
        None,
        Google,
        Microsoft
    }
}
5.  To use this View Helper, first ensure you include your namespace <%@ Import Namespace=”jQueryVersions.Helpers” %>
6.  Then call the jQueryHelper, for example:   <%= jQueryHelper.jQueryCore(jQueryVersion.v132, CDN.Google) %>
Full source code available here
How do you handle multiple jQuery versions in your web applications?

In SharePoint 2007, most everything does get crawled and built into the index file, including site columns, page content, filenames and the actual contents of those documents.  We all know that in a normal document library, the body of a document is included in the index, but how about an attachment to a custom list item?

Yes, the body is included, however what is not included is the filename of that attachment.   These seems like it is a bug within SharePoint, that could be addressed in a future hot fix.  I can see no reason why the filename would not be included.

A few workarounds.

1.  Don’t use the attachment feature if you really need the filenames to appear in the index.  Use a document library.

2.  Create an event receiver for that custom list where upon any changes to that list item, it will abstract the filename of the attachment and stick it into a custom column that will be included in the index.

In SharePoint 2007, say you had a situation where you had a keyword embedded in a document.  Then a later revision to that document removed that keyword.  That keyword now only exists in the version history of that document, but not in the latest document.   Does the search crawl index the version history?   Absolutely!  Here’s the tricky part though.  When performing a search on that keyword, the search results gives you no indication that the keyword that you found is contained in an older version.  The document just appears in the search results.

How I verified this behavior:

1. Create a Word document with any unique word in the body, for example the word “Let’s go hokies”.

2.  Upload that document to a document library.  Ensure that you have Version History enabled.

3.  Force the content to be recrawled (or wait for next incremental crawl)

4.  Go to Search and search on keyword “hokies”.  You will find the document.

5.  Edit that document and change body text to “Let’s go Spartans”.  No more “hokies” key word.

6.  Check that document back in.

7.  Force another recrawl of the content

8.  Search on “hokies”.  You still find the document within the search results, however, there is no visual indication that that keyword is contained in the version history and not the latest version.

In SharePoint 2007, by default, when you create new site collections within the same web application, they are all created in one content database.  There are various reasons why you might want each site collection created in it’s own dedicated content database.  One of those reasons is the 100 GB content database recommended best practice.   There is no option when using the Create Site Collection option to specify a different content database.  How would you do this?

1.  Go to Application Management > Content Databases

2.  Select content database and set to Offline.  Don’t worry, it does not mean offline like you think it means offline, taking the database offline.  It merely prevents any new site collections from being created within this content database.

3.  Create a new Content Database.  By default, it will be created in Online state, ready to receive any new site collections created in it.

4.  Go to Application Management > Create Site Collection and create your site collection.  Notice it gets created in your new online content database.

Repeat this technique to control which content database your new site collection is created in.

Want to know what happens if you attempt to create a site collection when all the content databases are offline?

“No content databases are available for this operation”

Always ensure you have at least one content database that is in online state.