本文介绍了DbSet.Cast< TEntity>()错误:无法创建一个DbSet< IEntity>从非通用DbSet为“实体”类型的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

版本信息:



我使用C#4.5,实体框架6.0和MEF



编码和单元测试



我创建了一个测试项目来解释这个问题:



请打开的UnitTest项目并尝试运行TestIfItWorks()单元测试。



问题



我想一个非通用DbSet转换成它的通用版本,但我得到了以下异常: InvalidCastException的:无法创建DbSet< IUSER>从非普通DbSet型用户的对象

  VAR非通用=上下文。设置(typeof运算(用户)); 
无功通用= nonGeneric.Cast<&IUSER GT;(); //异常这里



User类正在实施IUSER所以你会觉得演员不应该除非DbSet代码的问题仅限于具体类(但愿不是,否则我需要或者创建一个围绕非通用DbSet的包装将其转换为一个通用的DbSet或找到当前DbSet实现替代)。



如果即使他们目前不支持由Microsoft你想知道为什么我使用的接口,我给你解释一下(希望这将筛选出的反应是说:不这样做,而不是提供解决方案)的:



我使用MEF和的EntityFramework创建一个松散耦合的数据层引擎,通过它我可以提供每个项目的基础实体(及其相应的配置) 。我一直在使用广泛的接口来定义引擎。元数据,并在上下文中的具体实现实体使用MEF在运行时发现的。



从代码摘录



  [ TestMethod的] 
公共无效TestIfItWorks()
{
// TODO:请打开App.Config中,改变PluginsPath到你的机器相匹配的Plugins文件夹。使用

(VAR的DbContext =新MyContext())//请忽略这条线现在。这是的UnitOfWork我与上下文改为创建一个简单的单元测试
{
dbContext.Setup(); //请忽略这条线现在。这是的UnitOfWork的一部分,我搬到这里创建一个简单的单元测试

//所有这些的目的是为了能够读取和/写入用户信息数据库,同时用户定义类在外部装配
//但是我们可以通过使用MEF IUSER接口导入。

//失败的尝试#1:使用用户级直接!这并不工作,因为用户是在我们没有参考
// VAR外部类failedAttempt1 = dbContext.Set<使用者>();

//失败的尝试#2:但好消息是,我们能够获得IUSER和出口
//然后让获得DbSet<&IUSER GT;而不是
VAR failedAttempt2 = dbContext.Set<&IUSER GT;();

{
VAR throwsException2 = failedAttempt2.FirstOrDefault();
}
赶上(InvalidOperationException异常前)
{
// InvalidOperationException异常:
//的实体类型IUSER是不是该机型为当前上下文的一部分。
//它,当我试图定义从EntityTypeConfiguration<继承的类也没有工作; IUSER>对于TestImplementation
}




// OK然后让做不同的这个时候。让我们得到用户类型(即我们知道我们有良好的配置)
//从我们的集装箱,并要求上下文给我们的非通用版本
VAR userImplementationType = Logic.Instance.GetExportedTypes<&IUSER GT;()。 FirstOrDefault();
Assert.IsNotNull(userImplementationType,我们没有带能够TestImplementation加载到目录中,请确保PluginsPath在App.Config中正确设置。);
VAR非泛型= dbContext.Set(userImplementationType);
//
//这是工作,到目前为止,我们可以添加使用
// DbSet的非通用版本从数据库中删除记录。您可以取消以下代码块提供了一个独特的ID
//并测试它自己。
//
VAR NEWUSER = Logic.Instance.New<&IUSER GT;();
newUser.Id =99;
newUser.UserName =Aidin Sadighi
nonGeneric.Add(NEWUSER);

{
dbContext.SaveChanges();
}
赶上(DbUpdateException前)
{
//这是可以的,因为很可能这是一个重复的用户。只是增加了标识,以使其唯一。
}



//失败的尝试#3:铸造非通用DbSet仿制

{
// TODO:我需要解决这个问题。请帮我
VAR genericSet = nonGeneric.Cast<&IUSER GT;();
}
赶上(InvalidCastException的前)
{
//不能创建一个DbSet<&IUSER GT;从非普通DbSet型用户的对象。
抛出;
}
}
}


解决方案

对于这一点,我真的建议使用反射。在你的DbContext的构造函数,你可以设置一个属性来函数指针:

  =方法this.GetType()GetMethod (设置,新类型[0])MakeGenericMethod(typeof运算(UserImplementation))。 

您可以再调用这个使用:

  method.Invoke(这一点,新的对象[0]​​); 

这应该返回类型的对象 DbSet< UserImplementation> 其中.Cast<>()方法则可以调用在


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.

Problem

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

[TestMethod]
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>();
        try
        {
            var throwsException2 = failedAttempt2.FirstOrDefault();
        }
        catch (InvalidOperationException ex)
        {
            //InvalidOperationException: 
            // 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";
        nonGeneric.Add(newUser);
        try
        {
            dbContext.SaveChanges();
        }
        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
        try
        {
            //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'.
            throw;
        }
    }
}
解决方案

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.

这篇关于DbSet.Cast&LT; TEntity&GT;()错误:无法创建一个DbSet&LT; IEntity&GT;从非通用DbSet为“实体”类型的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-21 04:29