Implementing a generic repository with table-agnostic methods - c#

I'm working on refactoring a persistence layer to use a true generic repository, and want to minimise the number of similar queries being executed on different tables - think things like get by id from table a, b, or c, where the query only differs by the table.
My repository so far looks like this:
public interface IRepository<T>
{
void Insert(T entity);
void Update(T entity);
}
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
/// ctor stuff omitted ...
public void Insert(TEntity entity)
{
_db.Insert<TEntity>(entity);
}
public void Update(TEntity entity)
{
_db.Update<TEntity>(entity);
}
}
public interface IDerivedRepository : IRepository<MyEntity>
{
// defines interface methods not found on the base IRepository
}
public class DerivedRepository : BaseRepository<MyEntity>, IDerivedRepository
{
// implements methods defined on IDerivedRepository, and inherits Insert and Update from BaseRepository
}
This works nicely in that any new repository can inherit the methods defined on the base repo, which are type agnostic in that I can simply send an entity and my ORM (NPoco) manages the insert/update.
I want to extend that to allow generic base definitions for simple get/fetch type methods - get by id or a simple count being obvious examples. At the moment, I implement these in the appropriate repository so end up with multiple repository methods (in separate repositories) calling essentially the same code.
Example below is simplified (_db manages scope etc) but highlights what I'm trying to avoid - the repeated GetById methods where the table and return type differ
public class DerivedRepositoryA : BaseRepository<A>, IDerivedARepository
{
public A GetById(int id) {
return _db.Fetch<A>("select * from TableA where id = #0", id);
}
}
public class DerivedRepositoryB : BaseRepository<B>, IDerivedBRepository
{
public B GetById(int id) {
return _db.Fetch<B>("select * from TableB where id = #0", id);
}
}
public class DerivedRepositoryC : BaseRepository<C>, IDerivedCRepository
{
public C GetById(int id) {
return _db.Fetch<C>("select * from TableC where id = #0", id);
}
}
Is it possible, and how might I go about it?

The below BaseRepository<TEntity> implementation uses the type name as the table name by default, but allows for a custom table name which differs from the type name if required.
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly string tableName;
public BaseRepository() : this(typeof(TEntity).Name)
{
}
public BaseRepository(string tableName)
{
this.tableName = tableName;
}
public TEntity GetById(int id)
{
return _db.Fetch<TEntity>($"select * from Table{tableName} where id = {id}");
}
}

You don't need the table name, this would work
return _db.Single<TEntity>("where id = #id", id); //Or Fetch
You could do something like this and let NPoco handle the SQL. You can also use this for a Save< T >() or Delete < T >() also
public T GetByID<T>(Int32 ID)
{
try
{
if (ID == 0)
throw (new ArgumentNullException("ID cannot be 0"));
return _db.SingleOrDefaultById<T>(ID);
}
catch { throw; }
}

Related

EF Core, DI, Repository pattern and issue with base repository structure

I have .net core rest api, which contains hybrid structure in which it only contains repositories and not the service layer.
Now, there is one issue that I am facing with base repository and main structure. let me explain the issue first.
So, consider one entity. let's say Product and below is the definition for that entity. this entity has one base class called FullAuditedEntity.
[Table(name: "Products")]
public class Product : FullAuditedEntity
{
public string Name { get; set; }
}
public class FullAuditedEntity: IFullAuditedEntity
{
public FullAuditedEntity() { }
[Key]
public virtual int Id { get; set; }
}
public interface IFullAuditedEntity
{
int Id { get; set; }
}
The Base repository and it's interfaces are as below.
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IFullAuditedEntity, new()
{
private readonly ApplicationContext context;
public EntityBaseRepository(ApplicationContext context)
{
this.context = context;
}
public virtual IEnumerable<T> items => context.Set<T>().AsEnumerable().OrderByDescending(m => m.Id);
public virtual T GetSingle(int id) => context.Set<T>().FirstOrDefault(x => x.Id == id);
}
public interface IEntityBaseRepository<T> where T : class, new()
{
IEnumerable<T> items { get; }
T GetSingle(int id);
}
So, my Product repository will be like this.
public interface IProductRepository : IEntityBaseRepository<Product> { }
public class ProductRepository : EntityBaseRepository<Product>, IProductRepository
{
private readonly ApplicationContext context;
public ProductRepository(ApplicationContext context) : base(context: context)
{
this.context = context;
}
}
Now, up-to here everything is good, I can access this repository in controllers and can perform the actions that are listed in base class.
Issue I am facing : So with this structure, If I tries to add any new entity without FullAuditedEntity (see Product entity above, I have base class full audited entity over there), my structure of repository fails and it gives error.
let's say if I tries to add new entity Implementation, and this new entity has a random Id, so I do not want to inherit the FullAuditedEnitity base class. now in this case most of the thing will work fine but when I will try to create repository for Implementation entity, it will give generic error. see below snap of that.
What I tried so far...
I was thinking to create a parallel Base repository which does not inherit FullAuditedEntity as a generic class but I am not sure if it's best practice or not. also my concern is that what if I am doing any mistake in my current structure of repository pattern and Dependency injection?
Any help world be best and really appreciated.
Thank you in advance for your time.
Repositories are usually mapped to database tables. Database table should always have some column which can uniquely identify the row in table and it is common practice to call this column as Id. So you correctly implemented your FullAuditedEntity as there is Id property. However, your Id has always type of int. I suggest you to use the following construction and then your Id would be any type of struct such as int, decimal, Guid, and etc:
/// <summary>
/// Abstraction of the Entity
/// </summary>
public interface IEntity
{
object Id { get; set; }
}
/// <summary>
/// Base class for IDs
/// </summary>
public abstract class Entity<T>: IEntity where T: struct
{
public T Id { get; set; }
object IEntity.Id
{
get { return Id; }
set {
Id = (T)value;
}
}
}
public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IEntity, new()
{
// The code is omitted for the brevity
}
In addition, try to avoid entities without Id like Implementation as in future you will have to figure out how to find rows without Id in your database table.
UPDATE:
If you do not want to inherit FullAuditedEntity, then you can create BaseRepository<T> and then derive it in the EntityBaseRepository.
public abstract class BaseRepository<T> : IEntityBaseRepository<T> where T : class, new()
{
public virtual IEnumerable<T> items => throw new NotImplementedException();
public virtual T GetSingle(int id)
{
throw new NotImplementedException();
}
}
public class EntityBaseRepository<T> : BaseRepository<T> where T : class
, IFullAuditedEntity, new()
{
public override IEnumerable<T> items => base.items;
public override T GetSingle(int id)
{
return base.GetSingle(id);
}
}
and then your Implementation repository:
public interface IImplementationRepository : IEntityBaseRepository<Implementation> { }
public class ImplementationRepository: BaseRepository<Implementation>
, IImplementationRepository
{
public override Implementation GetSingle(int id)
{
return base.GetSingle(id);
}
}
UPDATE 1:
In my view, it is better to use services(Service layer) which consume ITRepository<T>.
Because it gives to you new abilities such as:
Add some calculations on data which got by Repository
Remap your entities which are pulled by the Repository
It is one additional layer of decoupling. So when you edit your service layer, then you don't need to edit Repository layer and then recompile your assembly

C# : Extending Generic class

partial class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
}
My generic repository implements a common set of methods for TEntity like
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>()
}
which I can access like
Repository<User>().Get();
Many repositories does the same set of operation, so it is beneficial but now I want to extend Repository<User> to support some additional behavior.
partial class Repository<User> : IRepository<User>
{
public user DoMagicFunction()
{
}
}
so that I can use the repository like
Repository<User>().DoMagicFunction();
how can I extend the same generic class for Some Tentity to extend new behaviour instead of modifying it.
I could have done the same like creating another UserRepository to support new feature, but the accessor would become
UserRepository.DoMagicFunction();
but I want it to be like
Repository<User>().DoMagicFunction();
You can use an extension method:
public static class ExtensionMethods {
public static User DoMagicFunction(this Repository<User> repository) {
// some magic
return null; //or another user
}
}
This will thus add the function in a syntactically nice way to Repository<User> objects.
In case you want to support it not only for Users, but for subclasses of Users as well, you can make the function generic:
public static class ExtensionMethods {
public static TEntity DoMagicFunction<TEntity>(this Repository<TEntity> repository)
where TEntity : User {
// some magic
return null; //or another TEntity
}
}
C# has a language feature called Extension Methods, you probably are using them from the .NET framework without knowing (e.g. the linq extensions methods). It's common to extend your classes or even your interfaces with extension methods without breaking the functionality of your code. Here is an example for your case.
Suppose you have a generic IRepository interface:
public interface IRepository<TEntity> where TEntity : class, IEntity
{
IQueryable<TEntity> Entities { get; }
}
This interface adheres to the SOLID principles, especially the O and I principle.
Now suppose IEntity looks like this:
public interface IEntity
{
int Id { get; }
}
Now you could perfectly imagine an often reusable extension method like this:
public static class RepositoryExtensions
{
// similar to your MagicFunction
public static TEntity GetById<TEntity>(this IRepository<TEntity> repository, int id)
where TEntity : class, IEntity
{
return repository.Entities.Single(entity => entity.Id == id);
}
}
In a similar manner you could also extend your Repository class
public static class RepositoryExtensions
{
public static TEntity GenericMagicFunction<TEntity>(this Repository<TEntity> repository)
{
//do some stuff
}
}
You can now consume that like this:
var repository = new Repository<User>();
var user = repository.GenericMagicFunction();
You could also limit your extension method:
public static class RepositoryExtensions
{
public static User DoMagicFunction(this Repository<User> repository)
{
//do some stuff
}
}
But doing this will defeat it's purpose, you could rather just implement this in the Repository<User> class.
If your system and architecture uses Dependency Injection, you're probably injecting an IRepository<User> to your consuming classes. So the first or second extension method examples I've provided would make the most sense.
If you want to extend any repository you can do it like this.
public static class RepositoryExtension
{
public static void MagicMethod<TEntity>(this IRepository<TEntity> repo) where TEntity: class
{
....
}
}
For a specific repository (eg User repository) you can use a similar process
public static class RepositoryExtension
{
public static void MagicMethod(this IRepository<User> repo)
{
....
}
}
Extension methods are not the way to go, because the code that implements the method can only access public/internal members of the class they extend and you are likely to want your repository's DataContext to be private.
In my opinion, your approach needs to be changed slightly.
What if in the future you want to add a Delete method to your generic repository, but you have some entities that should never be deleted? You'll end up with an instance of a repository for something like PurchaseOrder that you'll either have to remember to never call delete on or you will have to create a descendant of Repository<T> that throws an InvalidOperationException if called. Both of which are poor implementations.
Instead, you should delete your IRepository<T> interface completely. Keep your Repository<T> class, but explicitly define a repository interface for every entity that only has the methods you require.
public class Repository<TKey, TEntity>......
{
public TEntity Get<TEntity>(TKey key)....
public void Delete(TEntity instance)....
...etc...
}
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
// Note: No delete is exposed
}
MyDependencyInjection.Register<IPurchaseOrderRepository, Repository<PurchaseOrder, int>>();
When you need additional methods on your repository you add them to your IPurchaseOrderRepository and create a descendant of Repository<T>
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
void DoSomethingElse(int orderNumber);
}
public class PurchaseOrderRepository: Repository<PurchaseOrder, int> {
public void DoSomethingElse(int orderNumber) {.......}
}
MyDependencyInjection.Register<IPurchaseOrderRepository, PurchaseOrderRepository>();
Extension method is a best choice for this case.
Note: I have not checked but you should check Dependency Injection still works well as normal.
You can use below code for testing:
public class Employee
{
}
public class User
{
}
public interface IRepo<TEntity> where TEntity : class
{
TEntity Get(int id);
DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate);
DbContext GetContext();
}
public class Repo<TEntity> : IRepo<TEntity> where TEntity : class
{
DbContext _context;
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>();
}
public DbContext GetContext()
{
return _context;
}
}
public static class RepoExtensions
{
public static ChangeTracker DoMagic(this Repo<User> userRepo)
{
return userRepo.GetContext().ChangeTracker;
}
}
public static class Test
{
public static void DoTest()
{
Repo<User> repoUser = new Repo<User>();
repoUser.DoMagic();
Repo<Employee> repoEmployee = new Repo<Employee>();
//repoEmployee.DoMagic();
}
}

Generic repository with generic constructor of type T

I have the following classes in c#:
public class Customer{
public long Id { get; set;}
public String Firstname { get; set;}
public String Lastname { get; set;}
public Customer(long id, String firstname, String lastname){...}
}
public class Book{
public long Id { get; set;}
public String Title { get; set;}
public String Author{ get; set;}
public int NumberOfCopies{ get; set;}
public Book(long id, String title, String author, int numberofcopies){...}
}
My repository is generic and the interface is as follows:
public interface IGenericRepository<T> where T : class, new(){
Add(T entity);
Update(T entity);
Delete(T entity);
GetAll();
}
So to create a repository for a Customer I would create a IGenericRepository<Customer> and for a Book IGenericRepository<Book>. To access these methods from the GUI, I would need a method like: AddCustomer(long id, String firstname, String lastname) and the same for a book, because the GUI doesn't know the entities themselves. I was thinking to create a CustomerService and BookService which hold these methods.
But then I would have to create a new Service for every entity I add.
My question is, how can I make this service generic and still keep the parameters from the constructor of the entity?
To be clear, I would like a generic Service class, which can add both books and customers, but with the same method. So for example:
Add(<constructor parameters of T>)
This method will be called from a Controller class which will have all of the Service. The GUI can then access these service methods through the controller.
Is this possible? If yes, how? If no, is there a better solution to achieve this?
Thanks in advance!
One option is to accept the parameters as desired, e. g.:
public void Add<T>(params object param) { ... }
T is of the type which you want to create. Via reflection you check which constructors are available, chose the one that fits the list of parameters. Then instantiate the object. Voila.
They way I have typically seen it done is that you have the following:
1.
An interface that defines generic Add, Update, Delete, etc:
public interface IGenericRepository<T> where T : class
{
Add(T entity);
Update(T entity);
Delete(T entity);
GetAll();
}
2.
A generic repository that accepts the different types you are going to be persisting to your data store.
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private connectionInformation;
public GenericRepository<T>(object connectionInformation)
{
// do something with the connection info, dbContext, etc...
}
public T Add(T entity)
{
// implementation...
}
public T Update(T entity)
{
// implementation...
}
public T Delete(T entity)
{
// implementation...
}
public List<T> GetAll()
{
// implementation...
}
}
3.
A unit of work that sets up instances of your generic repositories for the different concrete types.
public class UnitOfWork
{
private object connectionInformation;
public UnitOfWork(object connectionInformation)
{
// set up your connection information
this.connectionInformation = connectionInformation;
this.CustomerRepository = new GenericRepository<Customer>(connectionInformation);
this.BookRepository = new GenericRepository<Book>(connectionInformation);
}
public GenericRepository<Book> BookRepository { get; private set; }
public GenericRepository<Customer> CustomerRepository { get; private set; }
}
4.
A service/services layer that can instantiate a "unit of work" from which you can interact with. It is the service that would be responsible for working with the different properties of each type, but the data saving and retrieving would be handled via the unitOfWork. In your service, you could have a method like this:
public void DeleteFirstBook()
{
var unitOfWork = new UnitOfWork(connnectionInformation);
var books = unitOfWork.BookRepository.GetAll();
if(books.Any())
{
unitOfWork.BookRepository.Delete(books.First());
}
}
You could also do the same for Customers. Having the service layer in place helps your code from being too tightly coupled. The "Data Layer" should only be responsible for interacting with the database (Create, Read, Update, Delete). As you stated, your UI layer should also not know how to create new objects, or interact with the database. So the service becomes important because it knows how to set up data, where to put the data, and how to return it back to the UI.
Hope it helps!
I would change the IRepository<t> method Add(T entity) to Add(object entity). That way you can use the exact same code for any entity.
Pretty standard approach is to pass "creator" delegate to your repository, also I'm not sure if it fits your goals:
public interface IGenericRepository<T> where T : class{
Add(Func<T> creator);
...
}
Repository<T> : IGenericRepository<T> where T : class
{
public Add(Func<T> creator)
{
T newOne = creator();
....
}
}
// usage
bookRepository.Add(() => new Book(42, "some title", ...));

C# repository implementation, need advice on generic fix

[Edited: The entities below are generated by Entity-Framework]
I am trying to implement a generic repository. Below are some interfaces that define specialize traits.
namespace AnimeVoter.DataLayer.Repositories
{
internal interface ICanCreate<TEntity>
{
void Create(TEntity entity);
}
internal interface ICanUpdate<TEntity>
{
bool Update(TEntity entity);
}
internal interface ICanDelete<TEntity>
{
bool Delete(TEntity entity);
}
internal interface ICanGetList<TEntity>
{
IEnumerable<TEntity> GetList();
}
internal interface ICanGetById<TEntity>
{
TEntity GetById(int id);
}
}
Now I also have an abstract class that combines the traits like below.
namespace AnimeVoter.DataLayer.Repositories
{
public abstract class CrudRepository<TEntity> :
ICanCreate<TEntity>,
ICanUpdate<TEntity>,
ICanDelete<TEntity>,
ICanGetList<TEntity>,
ICanGetById<TEntity>
{
public abstract void Create(TEntity entity);
public abstract bool Update(TEntity entity);
public abstract bool Delete(TEntity entity);
public abstract IEnumerable<TEntity> GetList();
public abstract TEntity GetById(int id);
}
}
Then I have somewhere like 10-15 concrete classes that uses the abstraction above. I will show only two. I will also limit the discussion to the common method Create().
Below is for the User table in the database:
namespace AnimeVoter.DataLayer.Repositories.Impl
{
public class UserRepository : CrudRepository<User>, IDisposable
{
DbEntities db = new DbEntities();
public override void Create(User entity)
{
db.Users.AddObject(entity);
}
...
And below is for the Title table in the database:
namespace AnimeVoter.DataLayer.Repositories.Impl
{
public class TitleRepository : CrudRepository<Title>, IDisposable
{
DbEntities db = new DbEntities();
public override void Create(Title entity)
{
db.Titles.AddObject(entity);
}
...
So there's the problem! When I am adding a new record to the User table I do db.Users.AddObject(entity). And when adding to the Title table I do db.Titles.AddObject(entity).
I am now wondering how I can refactor this using generics so I can just do something like db<"TableName">.AddObject(entity) or anything to that effect so I can have just one implementation for all the tables instead of having many implementations for each one of them?
The main thing you need to do is create an ObjectSet for the entity and then perform your actions against that ObjectSet instance. Here is a complete example on how to create a generic repository that handles all the CRUD actions.
public class TitleRepository : CrudRepository<Title>
{
public TitleRepository()
: base(new DbEntities())
{
}
}
public abstract class CrudRepository<TEntity> :
ICanCreate<TEntity>,
ICanUpdate<TEntity>,
ICanDelete<TEntity>,
ICanGetList<TEntity>,
ICanGetById<TEntity>
where TEntity : EntityObject
{
private readonly ObjectSet<TEntity> _objectSet;
private readonly string _primaryKey;
protected CrudRepository(ObjectContext context)
{
this._objectSet = context.CreateObjectSet<TEntity>();
this._primaryKey = this.GetPrimaryKeyPropertyName();
}
public void Create(TEntity entity)
{
this._objectSet.AddObject(entity);
this._objectSet.Context.SaveChanges();
}
public bool Update(TEntity entity)
{
if (entity.EntityState == EntityState.Detached)
{
this._objectSet.Attach(entity);
}
this._objectSet.Context.SaveChanges();
return true;
}
public bool Delete(TEntity entity)
{
this._objectSet.DeleteObject(entity);
this._objectSet.Context.SaveChanges();
return true;
}
public IEnumerable<TEntity> GetList()
{
return this._objectSet.ToList();
}
public TEntity GetById(int id)
{
return this._objectSet.Where(this.CreateGetByIdExpression(id)).FirstOrDefault();
}
// Build an Expression that can be used to query an Entity by Id.
private Expression<Func<TEntity, bool>> CreateGetByIdExpression(object id)
{
ParameterExpression e = Expression.Parameter(typeof(TEntity), "e");
PropertyInfo pi = typeof(TEntity).GetProperty(this._primaryKey);
MemberExpression m = Expression.MakeMemberAccess(e, pi);
ConstantExpression c = Expression.Constant(id, id.GetType());
BinaryExpression b = Expression.Equal(m, c);
Expression<Func<TEntity, bool>> lambda = Expression.Lambda<Func<TEntity, bool>>(b, e);
return lambda;
}
// Use the EF metadata to get the primary key property name.
private string GetPrimaryKeyPropertyName()
{
return this._objectSet.Context
.MetadataWorkspace
.GetEntityContainer(this._objectSet.Context.DefaultContainerName, DataSpace.CSpace)
.BaseEntitySets
.First(meta => meta.ElementType == this._objectSet.EntitySet.ElementType)
.ElementType.KeyMembers
.Select(k => k.Name)
.FirstOrDefault();
}
}
To accomplish this you have to define such mappings between entity type and db table. You can consider something like DbContractFactory and inject it in base CrudRepository<TEntity> class, so it will be able to retrieve Table reference/name in runtime based on current entity type TEntity like
dbContractFactory.GetDbContract<TEntity>()
In this way you can separate db-specifics from entities implementation itself by storing all relations in such factory/map.
EDIT: An example
interface IDbContract
{
string TableName { get; }
}
public sealed class DbContractFactory
{
private readonly IDictionary<Type, IDbContract> dbContractMap;
public void RegisterContract<TEntity>(IDbContract)
{
// store in dbContractMap
}
public IDbContract GetDbContract<TEntity>()
{
if (dbContractMap.Contains(typeof(TEntity))
{
// retrieve and return
}
}
}
Just replace the db.Title with CreateObjectSet
I do it something like this:
public class CrudRepository<TEntity> where TEntity : class
{
DbEntities db = new DbEntities();
public override void Create(TEntity entity)
{
db.CreateObjectSet<TEntity>().AddObject(entity);
}
}
EDIT:
Forgot the where...
I have found the answer here, http://geekswithblogs.net/seanfao/archive/2009/12/03/136680.aspx. This is very good because it eliminates having multiple repository objects for each table mapped by EF particularly for mundane operations like CRUD, which is exactly what I was looking for.

EntityFramework repository template - how to write GetByID lambda within a template class?

I am trying to write a generic one-size-fits-most repository pattern template class for an Entity Framework-based project I'm currently working on. The (heavily simplified) interface is:
internal interface IRepository<T> where T : class
{
T GetByID(int id);
IEnumerable<T> GetAll();
IEnumerable<T> Query(Func<T, bool> filter);
}
GetByID is proving to be the killer. In the implementation:
public class Repository<T> : IRepository<T>,IUnitOfWork<T> where T : class
{
// etc...
public T GetByID(int id)
{
return this.ObjectSet.Single<T>(t=>t.ID == id);
}
t=>t.ID == id is the particular bit I'm struggling with. Is it even possible to write lambda functions like that within template classes where no class-specific information is going to be available?
I've defined a interface:
public interface IIdEntity
{
long Id { get; set; }
}
And modified the t4 template which generates my POCO classes so that every class must implement the public interface IIdEntity interface.
Like this:
using System.Diagnostics.CodeAnalysis;
public partial class User : IIdEntity
{
public virtual long Id
{
get;
set;
}
With this modification I can write a generic GetById(long id) like:
public T GetById(long id)
{
return Single(e => e.Id == id);
}
The IRepository is defined as follows:
/// <summary>
/// Abstract Base class which implements IDataRepository interface.
/// </summary>
/// <typeparam name="T">A POCO entity</typeparam>
public abstract class DataRepository<T> : IDataRepository<T>
where T : class, IIdEntity
{
You could just create a small interface containing the Id-property and have T be constrained to types that implement it.
EDIT:
Based on the comment, if you accept the fact that the compiler wont be helping you ensure that the Id property actually exists you might be able to do something like this:
public class Repo<T> where T : class
{
private IEnumerable<T> All()
{
throw new NotImplementedException();
}
private bool FilterOnId(dynamic input, int id)
{
return input.Id == id;
}
public T GetById(int id)
{
return this.All().Single(t => FilterOnId(t, id));
}
}

Categories