为什么我不能使这个通用存储库工作?怎么了?

时间:2012-01-12 00:19:05

标签: generics c#-4.0 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);
    }

这里具体实施......

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();
    }
}

当我创建一个特定的存储库时......它说Tkey必须是引用类型,但为什么呢?有没有办法让这个通用存储库工作?使用TKey是为了使方法SelectByKey接受密钥类型。

编辑#1:

如果我删除约束,那么我还有另一个问题......在我的SelectByKey方法中使用== as lambda表达式无法将TKey与TKey进行比较。

编辑#2:

尝试使用Equals,语法似乎没问题。

编辑#3:

在运行时等于崩溃。说Tkey(似乎是一个System.Object)不能使用看起来不合逻辑的等号,因为对象具有相同的方法。我目前无法访问真实代码,但我使用下面的代码进行了一些测试..

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>
{
}

它似乎工作得很好。所以今晚我会试试。

编辑#4

好的,我得到的异常是Canoot创建类型为“System.Object”的常量值。此上下文仅支持主要类型,如int32,string和guid。

4 个答案:

答案 0 :(得分:2)

在您的存储库声明中

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

您已指定了只允许引用类型的类约束。参见

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

  

其中T:class

     

type参数必须是引用类型,包括任何类,   接口,委托或数组类型。 (见下面的注释。)

删除:class约束以允许任何类型。

除非您参与学习练习,否则我不会尝试从头开始构建您的存储库。我会利用别人的所作所为。当我编写存储库框架时,我想要一个GetById方法,该方法可以使用不同类型的主键(尽管不是多列主键)。在撰写时,我发现以下两篇文章特别有用:

C# LINQ to SQL: Refactoring this Generic GetByID method

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

答案 1 :(得分:0)

  

它说Tkey必须是参考类型,但为什么?

你有约束:

  

where TKey : class

你需要约束吗?您想支持哪些关键类型?

答案 2 :(得分:0)

添加

where TKey : IEquatable<TKey>

应解决问题并允许您使用Equals语法。

答案 3 :(得分:0)

如果您使用f12键查看guid或int元数据,您将会实现它:

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

然后约束将是:

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

和IEntity接口必须是这样的:

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

但是运算符==仍然不适合我,但是Equals方法按预期工作,仍然在寻找等于运算符的解决方案。

相关问题