runxc1 Bret Ferrier runxc1 Bret Ferrier - 17 days ago 8
C# Question

Entity Framework 4: How to find the primary key?

I am trying to create a generic method using EF4 to find the primary key of an object.

example

public string GetPrimaryKey<T>()
{
...
}


To give more info I am working off of the Tekpub StarterKit and below is the class I am trying to get up and running

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Objects;
using System.Data.Objects.ELinq;
using System.Data.Linq;
using Web.Infrastructure.Storage.EF4;

namespace Web.Infrastructure.Storage {
public class EFSession:ISession {
PuzzleEntities _db;//This is an ObjectContext
public EFSession() {
_db = new PuzzleEntities();
}

public void CommitChanges() {
_db.SaveChanges();
}
/// <summary>
/// Gets the table provided by the type T and returns for querying
/// </summary>
private ObjectSet<T> GetObjectSet<T>() where T:class {
return _db.CreateObjectSet<T>();
}

private T GetByPrimaryKey<T>() where T: class
{
.....
}

public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T: class{

foreach (T item in All<T>().Where(expression))
{
GetObjectSet<T>().DeleteObject(item);
}
}

public void Delete<T>(T item) where T : class {
GetObjectSet<T>().DeleteObject(item);
}

public void DeleteAll<T>() where T : class {
foreach(T item in All<T>())
{
GetObjectSet<T>().DeleteObject(item);
}
}

public void Dispose() {
_db.Dispose();
}

public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T:class {
return GetObjectSet<T>().SingleOrDefault(expression);
}

public IQueryable<T> All<T>() where T : class {
return GetObjectSet<T>().AsQueryable();
}

public void Add<T>(T item) where T : class {
GetObjectSet<T>().AddObject(item);
}
public void Add<T>(IEnumerable<T> items) where T : class {
foreach (T item in items)
{
GetObjectSet<T>().AddObject(item);
}
}
public void Update<T>(T item) where T : class {
//nothing needed here
}
}
}

Answer

So I was finally able to find out how to get this to work. I wish I hadn't lost the link to the blog I read last night as I didn't write the code.

public T GetByPrimaryKey<T>(int id) where T : class
{
    return (T)_db.GetObjectByKey(new EntityKey(_db.DefaultContainerName + "." + this.GetEntityName<T>(), GetPrimaryKeyInfo<T>().Name, id));
}

string GetEntityName<T>()
{
    string name = typeof(T).Name;
    if (name.ToLower() == "person")
        return "People";
    else if (name.Substring(name.Length - 1, 1).ToLower() == "y")
        return name.Remove(name.Length - 1, 1) + "ies";
    else if (name.Substring(name.Length - 1, 1).ToLower() == "s")
        return name + "es";
    else
        return name + "s";
}

private PropertyInfo GetPrimaryKeyInfo<T>()
{
    PropertyInfo[] properties = typeof(T).GetProperties();
    foreach (PropertyInfo pI in properties)
    {
        System.Object[] attributes = pI.GetCustomAttributes(true);
        foreach (object attribute in attributes)
        {
            if (attribute is EdmScalarPropertyAttribute)
            {
                if ((attribute as EdmScalarPropertyAttribute).EntityKeyProperty == true)
                    return pI;
            }
            else if (attribute is ColumnAttribute)
            {

                if ((attribute as ColumnAttribute).IsPrimaryKey == true)
                    return pI;
            }
        }
    }
    return null;
}

I hope this helps someone else. All I can say is that it should be a little clearer on how to do this.