DbSet.Cast() Error: Cannot create a DbSet from a non-generic DbSet for objects of type 'Entity'

c# casting dbset entity-framework mef


Version Info:

I am using C# 4.5, Entity Framework 6.0, and MEF.

Code and Unit Test

I created a Test Project to explain the problem: https://skydrive.live.com/redir?resid=E3C97EC293A34048!2234

Please Open the UnitTest project and try to run TestIfItWorks() unit test.


I want to convert a non-generic DbSet to its generic version but I am getting the following exception: InvalidCastException: Cannot create a DbSet<IUser> from a non-generic DbSet for objects of type 'User':

var nonGeneric = context.Set(typeof(User));
var generic = nonGeneric.Cast<IUser>(); //Exception in here

The User class is implementing IUser so you would think the cast shouldn't be a problem unless DbSet code is restricted to concrete classes (I hope not otherwise I need to either create a wrapper around non-generic DbSet to convert it to a generic DbSet or find an alternative to current DbSet implementation).

If you are wondering why I am using interfaces even though they are not currently supported by Microsoft I give you a little explanation (hopefully this would filter out responses that say "Don't Do That" instead of providing a solution) :

I am using MEF and EntityFramework to create a loosely coupled data layer engine through which I can provide Entities (and their corresponding configurations) per project basis. I have been using Interfaces extensively to define the engine. The meta data and concrete implementation of entities in context are discovered in run time using MEF.

Excerpt from code

public void TestIfItWorks()
    //TODO: Please open the App.Config and change the PluginsPath to match the Plugins folder in your machine.

    using (var dbContext = new MyContext()) //Please ignore this line for now. This was UnitOfWork which I replaced with Context to create a simple unit test
        dbContext.Setup(); //Please ignore this line for now. This was part of UnitOfWork which I moved to here to create a simple unit test

        //The purpose of all these is to be able to read and write user info from/to database while User class is defined in an external assembly
        //but we can import it by MEF using IUser interface.

        //Failed Attempt# 1: Use User class directly! This doesnt work because User is in an external class which we dont have reference to
        //var failedAttempt1 = dbContext.Set<User>(); 

        //Failed Attempt# 2: But the good thing is that we have access to IUser and its exports
        //then lets get a DbSet<IUser> instead
        var failedAttempt2 = dbContext.Set<IUser>();
            var throwsException2 = failedAttempt2.FirstOrDefault();
        catch (InvalidOperationException ex)
            // The entity type IUser is not part of the model for the current context.
            // It also didnt work when I tried to define a class that inherits from EntityTypeConfiguration<IUser>at TestImplementation

        //Ok then lets do it differently this time. Lets get User type (that we know we have good configuration for)
        //from our Container and ask Context to give us the nonGeneric version
        var userImplementationType = Logic.Instance.GetExportedTypes<IUser>().FirstOrDefault();
        Assert.IsNotNull(userImplementationType, "We havn't been able to load TestImplementation into catalog. Please ensure the PluginsPath is set correctly at App.Config");
        var nonGeneric = dbContext.Set(userImplementationType);
        // This is working so far, we can add and remove records from database using
        // the nonGeneric version of DbSet. You can uncomment the following code block provide a unique ID
        // and test it yourself.
        var newUser = Logic.Instance.New<IUser>();
        newUser.Id = "99";
        newUser.UserName = "Aidin Sadighi";
        catch (DbUpdateException ex)
            //This is OK because most probably this is a duplicate user. Just increase the Id to make it unique.

        //Failed Attempt#3: Cast non generic DbSet to generic
            //TODO: I need to fix this. Help me please 
            var genericSet = nonGeneric.Cast<IUser>();
        catch (InvalidCastException ex)
            //Cannot create a DbSet<IUser> from a non-generic DbSet for objects of type 'User'.
8/17/2015 11:23:39 AM

Accepted Answer

For this, I would actually suggest using reflection. In the constructor of your DbContext, you can set a property to the function pointer:

method = this.GetType().GetMethod("Set", new Type[0]).MakeGenericMethod(typeof(UserImplementation));

You can then invoke this using:

method.Invoke(this, new object[0]);

And this should return an object of type DbSet<UserImplementation> which the .Cast<>() method can then be invoked on.

10/19/2015 1:53:17 PM

Popular Answer





Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow