实体框架、LINQ 和泛型
我有以下代码:
public interface IKeyed<TKey>
{
TKey Id { get; }
}
// This is the entity framework generated model. I have added the
// IKeyed<Guid> interface
public partial class Person : IKeyed<Guid>
{
public Guid Id { get; set; }
}
public class Repository<TKey, TEntity> : IKeyedRepository<TKey, TEntity>
where TEntity : class, IKeyed<TKey>
{
private readonly IObjectSet<TEntity> _objectSet;
public Repository(IOjectSet<TEntity> objectSet)
{
_objectSet = objectSet;
}
public TEntity FindBy(TKey id)
{
return _objectSet.FirstOrDefault(x => x.Id.Equals(id));
}
}
[更新] 这是我的调用方式:
Db2Entities context = new Db2Entities(_connectionString); // This is the EF context
IObjectSet<Person> objectSet = context.CreateObjectSet<Person>();
IKeyedRepository<Guid, Person> repo = new Repository<Guid, Person>(objectSet);
Guid id = Guid.NewGuid();
Person person = repo.FindBy(id); // This throws the exception.
上面的代码编译。执行“FindBy”方法时,出现以下错误:
无法创建“闭包类型”类型的常量值。在这种情况下,仅支持原始类型(例如 Int32、String 和 Guid)。
由于我的“Id”类型是 Guid(支持的原始类型之一),看来我应该能够按摩这进入工作。
有人知道这是否可能吗?
谢谢,
鲍勃
I have the following code:
public interface IKeyed<TKey>
{
TKey Id { get; }
}
// This is the entity framework generated model. I have added the
// IKeyed<Guid> interface
public partial class Person : IKeyed<Guid>
{
public Guid Id { get; set; }
}
public class Repository<TKey, TEntity> : IKeyedRepository<TKey, TEntity>
where TEntity : class, IKeyed<TKey>
{
private readonly IObjectSet<TEntity> _objectSet;
public Repository(IOjectSet<TEntity> objectSet)
{
_objectSet = objectSet;
}
public TEntity FindBy(TKey id)
{
return _objectSet.FirstOrDefault(x => x.Id.Equals(id));
}
}
[Update]
Here is how I am calling this:
Db2Entities context = new Db2Entities(_connectionString); // This is the EF context
IObjectSet<Person> objectSet = context.CreateObjectSet<Person>();
IKeyedRepository<Guid, Person> repo = new Repository<Guid, Person>(objectSet);
Guid id = Guid.NewGuid();
Person person = repo.FindBy(id); // This throws the exception.
The above code compiles. When the 'FindBy' method is executed, I get the following error:
Unable to create a constant value of type 'Closure type'. Only primitive types (for instance Int32, String and Guid) are supported in this context.
Since the type of my 'Id' is a Guid (one of the primitive types supported) it seems like I should be able to massage this into working.
Anyone know if this is possible?
Thanks,
Bob
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是行不通的。您无法调用
Equals
,因为 EF 不知道如何将其转换为 SQL。当您将表达式传递给FirstOrDefault
时,它必须始终是可以转换为 SQL 的代码。通过手动构建表达式树可能可以解决您的问题,但我可以参考 Stack Overflow 上已经讨论的其他解决方案。ObjectContext
提供名为GetObjectByKey
的方法,这正是您想要做的。问题是它需要 EntityKey 作为参数。以下两个答案展示了如何使用此方法以及如何获取 EntityKey :在您的情况下,代码不会那么复杂,因为您知道key 属性,因此您通常只需要类似这样的内容:
这里的问题是您无法从
IObjectSet
获取entitySetName
,因此您必须将其传递给存储库构造函数,或者必须传递对象集
。以防万一您将来想要使用 DbContext API (EFv4.1) 而不是 ObjectContext API,它会大大简化,因为
DbSet
提供Find
方法:It doesn't work this way. You cannot call
Equals
because EF doesn't know how to translate it to SQL. When you pass expression toFirstOrDefault
it must be always only code which can be translated to SQL. It is probably possible to solve your problem with some manual building of expression tree but I can reference other solutions already discussed on Stack Overflow.ObjectContext
offers method namedGetObjectByKey
which is exactly what you are trying to do. The problem is that it requiresEntityKey
as parameter. Here are two answers which show how to use this method and how to getEntityKey
:In your case the code will be less complicated because you know the name of the key property so you generally need only something like this:
The problem here is that you cannot get
entitySetName
fromIObjectSet
so you must either pass it to repository constructor or you must passObjectSet
.Just in case you will want to use DbContext API (EFv4.1) in the future instead of ObjectContext API it will be much simplified because
DbSet
offersFind
method: