Why isn't DbSet covariant?

牧云@^-^@ 提交于 2019-12-05 09:16:16
Gert Arnold

It looks like they could be covariant. But there is a host of differences between in-memory programming and programming against a query provider.

For Entity Framework to materialize an object from the data store it requires its exact type and the mapping from database columns to the type's properties. An interface can represent any type and EF is not (yet) able to pick a suitable implementation itself. Maybe support for interfaces will be featured in future releases.

The same applies to casting entities to an interface in an EF query (a case I just added to my list of differences).

DbSet<T> CANNOT be co-variant. Firstly, this is because in C#, classes cannot be co-variant...only interfaces. Secondly because DbSet<T> has both co-variant and contra-variant methods.

Take the following two examples.

DbSet<CategoryType> set = context.Set<CategoryType>();
IQueryable<IItemType> query = set.Where(x => x.Foo == Bar);

So we know for a fact that all CategoryTypes are IItemType, so we know this can always work.

However conversely try this...

DbSet<CategoryType> set = context.Set<CategoryType>();
IItemType newItemType = new ProductType();
set.Add(newItemType);  // Compiler error.

Not all IItemTypes are CategoryType. So if we could cast DbSet<CategoryType> to DbSet<IItemType> we would get run time errors when adding... Since the compiler knows that this might not always work, it won't let you do the casting.

However there are interfaces that DbSet<T> does allow Co-Variance on. You can try casting it to IQueryable<IItemType> for example.

However it sounds like you are trying to query against the DbSet using a query against the interface... try the following

DbSet<CategoryType> set = context.Set<CategoryType>();
IQueryable<IItemType> cast = set.OfType<IITemType>(); //(or .Cast<>() works too)
IQueryable<IItemType> query = cast.Where(x => x ....);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!