实体框架、LINQ 和泛型

发布于 2024-11-09 03:18:30 字数 1318 浏览 0 评论 0原文

我有以下代码:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小矜持 2024-11-16 03:18:30

这是行不通的。您无法调用 Equals,因为 EF 不知道如何将其转换为 SQL。当您将表达式传递给 FirstOrDefault 时,它必须始终是可以转换为 SQL 的代码。通过手动构建表达式树可能可以解决您的问题,但我可以参考 Stack Overflow 上已经讨论的其他解决方案。

ObjectContext 提供名为 GetObjectByKey 的方法,这正是您想要做的。问题是它需要 EntityKey 作为参数。以下两个答案展示了如何使用此方法以及如何获取 EntityKey :

在您的情况下,代码不会那么复杂,因为您知道key 属性,因此您通常只需要类似这样的内容:

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,因此您必须将其传递给存储库构造函数,或者必须传递对象集

以防万一您将来想要使用 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 to FirstOrDefault 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 named GetObjectByKey which is exactly what you are trying to do. The problem is that it requires EntityKey as parameter. Here are two answers which show how to use this method and how to get EntityKey:

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:

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

The problem here is that you cannot get entitySetName from IObjectSet so you must either pass it to repository constructor or you must pass ObjectSet.

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 offers Find method:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文