Rushino
Rushino

Reputation: 9485

Why i can't make this generic repository to work ? What wrong?

I have this generic repository.

 /// <summary>
/// Implémentation de base d'un dépositoire pour Entity Framework.
/// </summary>
/// <remarks>Entity Framework 4.1</remarks>
/// <typeparam name="TEntite">Entité spécifique.</typeparam>
public abstract class RepositoryBase<TEntity, TKey> : IRepository<TEntity>, IDisposable
    where TEntity : EntityBase<TKey>
    where TKey : class
{
    private readonly IContext _context;
    private ObjectContext _objectContext;
    private IObjectSet<TEntity> _objectSet;

    protected RepositoryBase(IContext context)
    {
        _context = context;
        _objectContext = _context.GetObjectContext();
        _objectSet = _objectContext.CreateObjectSet<TEntity>();
    }

    /// <see cref="IRepository.cs"/>
    public IEnumerable<TEntity> GetAll(Expression<Func<TEntity, object>> sortExpression)
    {
        if (sortExpression == null)
            sortExpression = x => x.Id;
        return _objectSet.OrderBy(sortExpression).AsEnumerable();
    }

    /// <see cref="IRepository.cs"/>
    public IEnumerable<TEntity> GetAll(int maximumRows, int startRowIndex, Expression<Func<TEntity, object>> sortExpression)
    {
        if (sortExpression == null)
            sortExpression = x => x.Id;
        return _objectSet.OrderBy(sortExpression).Skip(startRowIndex).Take(maximumRows).AsEnumerable();
    }

    /// <see cref="IRepository.cs"/>
    public TEntity SelectByKey(TKey key) 
    {
        if (key == null)
            throw new ArgumentNullException("La clé était NULL! Une clé est nécessaire pour récupérer un entité.");
        return _objectSet.SingleOrDefault(x => x.Id == key);
    }

Here the specific implementation...

public class ProductRepository : RepositoryBase<Product, int>, IProductRepository
{
    public ProductRepository(IContext context)
        : base(context)
    { }
    /// <see cref="IProductRepository.cs"/>
    public Product GetByName(string name)
    {
        return base.First(x => x.Name == name);
    }

    /// <see cref="IProductRepository.cs"/>
    public IEnumerable<Product> FindProduct(Specification<Product> specification)
    {
        throw new System.NotImplementedException();
    }
}

When i create a specific repository.. it say that Tkey must be a reference type but why ? Is there a way to make this generic repository work ? TKey was used in order to make the method SelectByKey accept a key type.

Edit #1:

If i remove the constrain then i have another problem... TKey cannot be compared with TKey using == as lambda expression in my SelectByKey method.

Edit #2:

Tried to use Equals and the syntax seem to be ok.

Edit #3:

Equals crash at runtime.. saying Tkey (which seem to be a System.Object) can't use equals which doesnt seem logic since object have the equal method. I currently doesn't have access to the real code but i did some test with this code below..

class Program
{
    static void Main(string[] args)
    {
        Test<TestEntity, int> t = new Test<TestEntity, int>();  
        t.TestMethod(5);
    }
}

class Test<TEntity, TKey>
    where TEntity : Entity<TKey>
{
    public Test()
    { }

    public TestEntity TestMethod(TKey id)
    {
        List<TestEntity> testEntity = new List<TestEntity>();
        testEntity.Add(new TestEntity(5));
        return testEntity.SingleOrDefault(x => x.Id.Equals(id));
    }
}

class Entity<TKey>
{
    public TKey Id { get; set; }
}

class TestEntity : Entity
{
    public TestEntity(int id)
    {
        Id = id;
    }
}

class Entity : Entity<int>
{
}

And it seem to work pretty well. So i will try later tonight.

Edit #4

Alright the exception i get is Canoot create a constant value of type "System.Object". Only primary types such int32, string and guid are supported by this context.

Upvotes: 1

Views: 1187

Answers (4)

Mouad Cherkaoui
Mouad Cherkaoui

Reputation: 78

If you take a look at guid or int metadata by using f12 key, you'll se that it implement:

public struct int: IFormatable, IComparable, IComparable<int>, IEquatable<int> 
public struct Guid: IFormatable, IComparable, IComparable<Guid>, IEquatable<Guid>

then the constraint will be :

public interface IRepository<TEntity, TKey> 
  where TEntity: class, IEntity<TKey>
  where TKey: struct, IFormatable, IComparable, IComparable<TKey>, IEquatable<TKey>

and IEntity interface must be like this:

public interface IEntity<TKey> where TKey: struct, IFormatable, 
                               IComparable, IComparable<TKey>, IEquatable<TKey>

but the operator == still not working for me, but the Equals method works as we expect, still searching for a solution for the equality operator.

Upvotes: 0

ctrlShiftBryan
ctrlShiftBryan

Reputation: 27740

Adding

where TKey : IEquatable<TKey>

Should fix the problem and allow you to use Equals syntax.

Upvotes: 0

In your repository declaration

public abstract class RepositoryBase<TEntity, TKey> : IRepository<TEntity>, IDisposable
    where TEntity : EntityBase<TKey>
    where TKey : class
{

you have specified the class constraint which will only allows reference types. See

http://msdn.microsoft.com/en-us/library/d5x73970%28v=vs.80%29.aspx

where T : class

The type argument must be a reference type, including any class, interface, delegate, or array type. (See note below.)

Remove the : class constraint to allow any type.

Unless you're engaged in a learning exercise, I would not try to build your repository from scratch. I would leverage off what others have done. When I wrote a repository framework, I wanted a GetById method that would work with primary keys of varying types (although not multiple column primary keys). When writing it, I found the following two posts especially helpful:

C# LINQ to SQL: Refactoring this Generic GetByID method

http://goneale.com/2009/07/27/linq-to-sql-generic-repository/

Upvotes: 3

David
David

Reputation: 2038

it say that Tkey must be a reference type but why ?

You have the constraint:

where TKey : class

Do you need the constraint? What key types do you want to support?

Upvotes: 0

Related Questions