我有以下代码:
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(支持的原始类型之一),我似乎应该能够将其按下来进行工作。
任何人都知道这是否可行?
谢谢,
鲍勃
答案 0 :(得分:3)
这种方式不起作用。您无法调用Equals
,因为EF不知道如何将其转换为SQL。将表达式传递给FirstOrDefault
时,它必须始终只是可以转换为SQL的代码。通过表达树的一些手动构建可能可以解决您的问题,但我可以参考已在Stack Overflow上讨论过的其他解决方案。
ObjectContext
提供名为GetObjectByKey
的方法,这正是您要尝试的方法。问题是它需要EntityKey
作为参数。以下是两个答案,说明如何使用此方法以及如何获取EntityKey
:
在您的情况下,代码将不那么复杂,因为您知道密钥属性的名称,因此您通常只需要这样的代码:
public virtual TEntity FindBy(TKey id)
{
// Build entity key
var entityKey = new EntityKey(_entitySetName, "Id", key);
// Query first current state manager and if entity is not found query database!!!
return (TEntity)Context.GetObjectByKey(entityKey);
}
此处的问题是您无法从entitySetName
获取IObjectSet
,因此您必须将其传递给存储库构造函数,或者必须传递ObjectSet
。
以防万一你将来想要使用DbContext API(EFv4.1)而不是ObjectContext API,因为DbSet
提供了Find
方法,所以它会大大简化: