Search code examples
c#repository-patterngeneric-collections

Find entity by TKey in Repository Pattern<T, TKey>


With Repository Pattern, I am trying to find an entity by TKey. I am trying to find the way to compare TKey with int

Implementation

public interface IRepository<T, TKey>
{
    T GetById(TKey id);
}

public class Repository<T, TKey> : IRepository<T, TKey> where T : class, IEntity<TKey>
{
    private List<T> _context;

    public Repository(List<T> context)
    {
        _context = context;
    }

    public T GetById(TKey id)
    {
        return _context.Single(m => m.Id == (TKey)id);
    }
}

Here, passing int for TKey

public interface IEntity<TKey>
{
    TKey Id { get; set; }
}

public class TestEntity : IEntity<int>
{
    public int Id { get; set; }

    public string EntityName { get; set; }
}

Finally, Test Client

var list = new List<TestEntity>();

list.Add(new TestEntity{ Id = 1 , EntityName = "aaa" });
list.Add(new TestEntity{ Id = 2 , EntityName = "bbb" });

var repo = new Repository<TestEntity, int>(list);
var item = repo.GetById(1);

Console.WriteLine(item);

I may not be in the right direction with casting the below way but tried and ran with an error.

public T GetById(TKey id)
{
    return _context.Single(m => (object)m.Id == Convert.ChangeType(id, typeof(TKey));
}

[System.InvalidOperationException: Sequence contains no matching element]

How to implement with the same approach without changing the parameter from TKey id to Expression<Func<T, bool>> predicate


Solution

  • You don't need all that casting, and definitely no string conversion, because first and foremost TKey == TKey, and second, not all underlying stores may be able to apply those conversions.

    You need to research the actual compiler error that your initial code gave:

    CS0019: Operator == cannot be applied to operands of type TKey and TKey

    In order to let C# know it can compare two TKeys, you need to constrain TKey to IEquatable<TKey> and call .Equals():

    public class Repository<T, TKey> : IRepository<T, TKey>
        where T : class, IEntity<TKey>
        where TKey : IEquatable<TKey>
    {
        private List<T> _context;
    
        public Repository(List<T> context)
        {
            _context = context;
        }
    
        public T GetById(TKey id)
        {
            return _context.Single(m => m.Id.Equals(id));
        }
    }