Friday, November 12, 2010

Find it and lose find it and lose it

Periodically, I need the ability to fetch any single item from an arbitrary Linq to SQL ITable based on the primary key value. I've seen this code elsewhere on the Internet, but every time I go looking for it I struggle to find it. So now I'm saving it here once for all. In this case the expectation is that my primary key ID is an integer, but int could easily be replaced by GUID or anything else.

public static class ITableHelpers
{
  public static object SingleOrDefaultByID(this ITable table, int id)
  {
    var param = Expression.Parameter(table.ElementType, "e");
    var predicate = Expression.Lambda(
      Expression.Equal(
        Expression.Property(param, table.PrimaryKey().Name),
        Expression.Constant(id)
      ),
      param
    );

    var call = Expression.Call(typeof(Queryable), "SingleOrDefault", new Type[] { table.ElementType }, table.Expression, predicate);
    return table.Provider.Execute(call);
  }

  public static System.Reflection.PropertyInfo PrimaryKey(this ITable table)
  {
    var matchingProperties = table.ElementType.GetProperties().Where(p => p.GetCustomAttributes(true).OfType<System.Data.Linq.Mapping.ColumnAttribute>().Any(c => c.IsPrimaryKey));

    if (matchingProperties.Count() != 1)
      throw new NotSupportedException(String.Format("Class '{0}' does not contain exactly one property that is a Linq to SQL primary key.", table.ElementType.FullName));

    return matchingProperties.Single();
  }
}

No comments: