I'm writing a LINQ to SQL based repository where I want to allow a GetByID with an int parameter. The signature is:
public T GetByID(int id)
{
     // Return
     return _dataContext.GetTable<T>() ....;
}
My tables have different names for the primary key. What I'd like to do is determine dynamically for each T what the primary key is and query it for a value of integer = id. Any ideas how to best pull this off?
Something like below (which supports other types than just int, but defaults to int). Importantly, don't fall into the trap of looking at Attribute data via reflection; LINQ-to-SQL supports objects without attributes too:
public static TEntity Get<TEntity>(this DataContext dataContext, int id)
        where TEntity : class
{
    return Get<TEntity, int>(dataContext, id);
}
public static TEntity Get<TEntity, TKey>(this DataContext dataContext, TKey id)
    where TEntity : class
{
    // get the row from the database using the meta-model
    MetaType meta = dataContext.Mapping.GetTable(typeof(TEntity)).RowType;
    if (meta.IdentityMembers.Count != 1) throw new InvalidOperationException(
        "Composite identity not supported");
    string idName = meta.IdentityMembers[0].Member.Name;
    var param = Expression.Parameter(typeof(TEntity), "row");
    var lambda = Expression.Lambda<Func<TEntity, bool>>(
        Expression.Equal(
            Expression.PropertyOrField(param, idName),
            Expression.Constant(id, typeof(TKey))), param);
    return dataContext.GetTable<TEntity>().Single(lambda);
}
                        Dennis Troller answered it to the question that Ben linked to in the comments in the question.
Personally, I think it would be easier to provide a SingleOrDefault<T> method that takes a Func<int,T> selector argument.  Then you can provide whatever selector you wish, including the one that selects based on that table's id.
 public abstract class Repository<T> where T : class
 {
     public abstract T GetById( int id );
     public T SingleOrDefault( Func<int,T> selector )
     {
           return _dataContext.GetTable<T>().SingleOrDefault( selector );
     }
 }
Usage:
 var myObj = repos.SingleOrDefault<MyClass>( c => c.MyClassID == id );
A strongly-typed respository could then use this method to implement GetById()
 public class MyClassRepository : Repository<MyClass>
 {
     public override MyClass GetById( int id )
     {
         return this.SingleOrDefault( c => c.MyClassID == id );
     }
 }
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With