为什么我无法使这个通用存储库正常工作?怎么了?
我有这个通用存储库。
/// <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
, IProductRepository { 公共 ProductRepository(IContext 上下文) :基础(上下文) { }
/// <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:
如果我删除约束,那么我还有另一个问题... TKey 无法在我的 SelectByKey 方法中使用 == 作为 lambda 表达式与 TKey 进行比较。
编辑#2:
尝试使用Equals,语法似乎没问题。
编辑#3:
等于在运行时崩溃..说Tkey(似乎是一个System.Object)不能使用equals,这似乎不符合逻辑,因为对象有equal方法。我目前无法访问真正的代码,但我用下面的代码做了一些测试..
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。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在存储库声明中,
您指定了仅允许引用类型的类约束。请参阅
http://msdn.microsoft.com /en-us/library/d5x73970%28v=vs.80%29.aspx
删除 : class 约束以允许任何类型。
除非您正在进行学习练习,否则我不会尝试从头开始构建您的存储库。我会借鉴其他人所做的事情。当我编写存储库框架时,我想要一个可以处理不同类型的主键(尽管不是多列主键)的 GetById 方法。在编写它时,我发现以下两篇文章特别有用:
C# LINQ to SQL:重构此通用 GetByID 方法
http://goneale.com/2009/07/27/linq -to-sql-generic-repository/
In your repository declaration
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
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/
你有这样的约束:
您需要约束吗?您想支持哪些关键类型?
You have the constraint:
Do you need the constraint? What key types do you want to support?
添加
应该可以解决问题并允许您使用 Equals 语法。
Adding
Should fix the problem and allow you to use Equals syntax.
如果您使用 f12 键查看 guid 或 int 元数据,您会发现它实现了:
那么约束将是 :
并且 IEntity 接口必须是这样的:
但运算符 == 仍然对我不起作用,但是Equals 方法按照我们的预期工作,仍在寻找相等运算符的解决方案。
If you take a look at guid or int metadata by using f12 key, you'll se that it implement:
then the constraint will be :
and IEntity interface must be like this:
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.