【问题标题】:Entity Framework, LINQ and Generics实体框架、LINQ 和泛型
【发布时间】:2011-08-29 23:01:48
【问题描述】:

我有以下代码:

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(支持的原始类型之一),我似乎应该能够将它按摩到工作中。

有人知道这是否可行吗?

谢谢,

鲍勃

【问题讨论】:

  • 如果我必须根据自己编写 linq 提供程序的冒险经历来判断,我假设 EF 的提供程序会按类型解析给定的表达式 first 或 default 。 id 的类型是 TKey,它不是 typeof(Guid)。
  • 我相信 TDaver 是对的。如果您有一个非泛型参数 Guid 而不是泛型 TKey 参数,则该代码实际上可以工作。

标签: entity-framework generics ado.net repository-pattern


【解决方案1】:

这种方式是行不通的。您不能调用 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);
}

这里的问题是您无法从IObjectSet 获取entitySetName,因此您必须将其传递给存储库构造函数,或者您必须传递ObjectSet

以防万一您将来想要使用 DbContext API (EFv4.1) 而不是 ObjectContext API,它将大大简化,因为 DbSet 提供 Find 方法:

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
  • 2018-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多