Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework: ObjectSet and its (generics) variance

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?

like image 793
Jefim Avatar asked Dec 21 '22 23:12

Jefim


2 Answers

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.

like image 144
Bennor McCarthy Avatar answered Jan 23 '23 18:01

Bennor McCarthy


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!

like image 38
Jefim Avatar answered Jan 23 '23 18:01

Jefim