实体框架:ObjectSet 及其(泛型)方差

发布于 2024-09-19 00:12:53 字数 985 浏览 7 评论 0原文

我使用:EntityFramework + POCO

事情是这样的:

public interface IBaseType
{
    int Id { get; set; }
}

public class BaseType : IBaseType
{
    public virtual int Id { get; set; }
}

public class DerivedType : BaseType
{
}

问题:

public class EntityFetcher<T> where T : BaseType
{
    public object GetById(int id)
    {
        ObjectSet<T> objectSet = (ObjectSet<T>)GetTheObjectSet(typeof(T)); 

        return objectSet.SingleOrDefault((o) => o.Id == id);
    }
}

如果 TBaseType 这一切都可以正常工作,但是: 问题是,在 EntityFramework 中,当一个类继承另一个类时,它们共享 ObjectSet,因此,如果 TDerivedType,则 GetTheObjectSet 返回 ObjectSet,它不能转换为 ObjectSet

有没有办法实际投射这个东西或以其他方式执行 SingleOrDefault ?可以使用 IObjectSetIBaseType 来转换这些东西吗?

I use: EntityFramework + POCO

Here is the thing:

public interface IBaseType
{
    int Id { get; set; }
}

public class BaseType : IBaseType
{
    public virtual int Id { get; set; }
}

public class DerivedType : BaseType
{
}

The problem:

public class EntityFetcher<T> where T : BaseType
{
    public object GetById(int id)
    {
        ObjectSet<T> objectSet = (ObjectSet<T>)GetTheObjectSet(typeof(T)); 

        return objectSet.SingleOrDefault((o) => o.Id == id);
    }
}

If T is BaseType this all works perfectly, but:
The problem is that in EntityFramework when one class inherits another they share the ObjectSet and, therefore, if T is DerivedType then the GetTheObjectSet returns ObjectSet<BaseType>, which cannot be cast to ObjectSet<DerivedType>.

Is there a way to actually cast this this thing or somehow else execute the SingleOrDefault? Can those things be cast using the IObjectSet<> and IBaseType?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(3

情话难免假 2024-09-26 00:12:53

我想您正在寻找这个:

public T GetById(int id)
{
    ObjectSet<T> objectSet = (ObjectSet<T>)GetTheObjectSet(typeof(T)); 

    return objectSet.OfType<T>().SingleOrDefault((o) => o.Id == id);
}

ObjectQuery 的 OfType 方法 (ObjectSet 派生自)将返回派生类型的对象。

I think you're looking for this:

public T GetById(int id)
{
    ObjectSet<T> objectSet = (ObjectSet<T>)GetTheObjectSet(typeof(T)); 

    return objectSet.OfType<T>().SingleOrDefault((o) => o.Id == id);
}

The OfType method of an ObjectQuery (which ObjectSet derives from) will return objects of the derived type.

ぺ禁宫浮华殁 2024-09-26 00:12:53

这个转换问题的答案如下:

public T GetById(int id)
{
    // The line that throws InvalidCast with T = DerivedType
    //ObjectSet<T> objectSet = (ObjectSet<T>)GetTheObjectSet(typeof(T));

    // This is a valid cast since ObjectSet<T> is derived from ObjectQuery
    ObjectQuery objectQuery = (ObjectQuery)GetTheObjectSet(typeof(T));
    return objectQuery.OfType<T>().SingleOrDefault((e) => e.Id == id);
}

解决方案是将 ObjectSet 转换为 ObjectQuery 并在那里进行查询。这里最重要的部分是 ObjectQuery 不是通用的,因此转换进行得很好。

我必须感谢 Bennor McCarthy,因为他是第一个向我指出 OfType + 转换为 ObjectQuery 的人(事实上,ObjectSet : ObjectQuery)。谢谢!

The answer to this casting problem was as follows:

public T GetById(int id)
{
    // The line that throws InvalidCast with T = DerivedType
    //ObjectSet<T> objectSet = (ObjectSet<T>)GetTheObjectSet(typeof(T));

    // This is a valid cast since ObjectSet<T> is derived from ObjectQuery
    ObjectQuery objectQuery = (ObjectQuery)GetTheObjectSet(typeof(T));
    return objectQuery.OfType<T>().SingleOrDefault((e) => e.Id == id);
}

The solution was to cast ObjectSet to ObjectQuery and do the query there. The most important part here is that ObjectQuery is not generic, so the cast goes through fine.

I must give some credits to Bennor McCarthy as he was the one to point me to OfType + casting to ObjectQuery (the fact that ObjectSet : ObjectQuery). Thanks!

淤浪 2024-09-26 00:12:53

我检查了我的一个测试项目,该项目目前距离可构建状态还很远,但这之前对我有用:

public interface IEntity
{
    int Id { get; }
    byte[] Timestamp { get; set; }
}

public abstract class Entity : IEntity
{
    public int Id { get; set; }
    public byte[] Timestamp { get; set; }
}

public class PocoData : Entity
{
   ...
}

public class Repository<T> : IRepository<T> where T : class, IEntity 
{
    protected ObjectContext Context;
    protected ObjectSet<T> ObjectSet;

    public Repository(ObjectContext context)
    {
        Context = context;
        ObjectSet = context.CreateObjectSet<T>();
    }

    public virtual T GetById(int id)
    {
        return ObjectSet.SingleOrDefault(o => o.Id == id);
    }

    ...
}

要点是实体类不是在 EDMX 文件中建模的。在 EDMX 文件中建模的所有实体都有自己的 Id 和时间戳,但我的 POCO 类使用共享基类。我使用了 Repository没有任何问题。

I checked one of my test projects which is currently far away from buildable state but this worked for me before:

public interface IEntity
{
    int Id { get; }
    byte[] Timestamp { get; set; }
}

public abstract class Entity : IEntity
{
    public int Id { get; set; }
    public byte[] Timestamp { get; set; }
}

public class PocoData : Entity
{
   ...
}

public class Repository<T> : IRepository<T> where T : class, IEntity 
{
    protected ObjectContext Context;
    protected ObjectSet<T> ObjectSet;

    public Repository(ObjectContext context)
    {
        Context = context;
        ObjectSet = context.CreateObjectSet<T>();
    }

    public virtual T GetById(int id)
    {
        return ObjectSet.SingleOrDefault(o => o.Id == id);
    }

    ...
}

The main point is that Entity class is not modeled in EDMX file. All entities modeled in EDMX file has its own Id and Timestamp but my POCO classes use shared base class. I used Repository<PocoData> without any problem.

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