使用实体框架进行向下转型

时间:2011-09-01 06:42:06

标签: c# entity-framework asp.net-mvc-3 casting downcast

我有一个项目,我在EF中将Employer定义为User的派生类。在我的过程中,我创建了一个用户而不知道它最终是否会成为雇主(或其他类型的用户),之后我需要转换它。起初我尝试过(Intellisense表示存在显式转换):

Employer e = (Employer) GetUser();

但是在运行时我得到了:

Unable to cast object of type 'System.Data.Entity.DynamicProxies.User_7B...0D' to type 'Employer'.

所以我试着写一个转换器:

public partial class User
{
    public static explicit operator Employer(User u)
    {

但是我收到了错误:

Error   21  'User.explicit operator Employer(User)': user-defined
conversions to or from a derived class are not allowed
C:\Users\..\Documents\Visual Studio 2010\Projects\..\Website\Models\EF.Custom.cs

细。然后我重载Employer的构造函数,如下所示:

public partial class Employer
{
    public Employer(User u)
    {
        this.Id = u.Id;
        this.Claims = u.Claims;
        // etc.
    }
}

并认为我可以这样做:

Employer e = new Employer(GetUser());

但是当我运行它时,我收到错误:

System.InvalidOperationException was unhandled by user code
  Message=Conflicting changes to the role 'User' of the
  relationship 'EF.ClaimUser' have been detected.
  Source=System.Data.Entity
  StackTrace:
       [...]
       at Controllers.AuthController.Register(String Company, String GivenName, 
       String Surname, String Title, String Department) in C:\Users\..\Documents\
       Visual Studio 2010\Projects\..\Website\Controllers\AuthController.cs:line

作为最后的手段我尝试写这个:

        Employer e = Auth.Claims("id")
            .Where(x => x.Value == Auth.NameIdentifier())
            .Select(x => x.User)
            .Cast<Employer>()
            .Single();

... GetUser()返回一个User类型的对象,它不提供.Cast<>所以我用直接查询到达那里......但我仍然得到动态代理的转换对象例外。

所以我的问题是:当对象通过EF保持持久性时,我怎么能转发?

2 个答案:

答案 0 :(得分:6)

这是不可能的。您必须始终使用最终类型。将其创建为User后,EF将永远不允许您将其更改为派生实体类型。

顺便说一下。对于面向对象的方法也是不可能的。您不能将父类的实例强制转换为派生类的实例(除非它确实是派生类的实例) - 它将在运行时抛出异常。很简单的例子来重现这个问题:

class X { } 

class Y : X { }

class Program 
{
    static void Main(string[] args) 
    {
        X x1 = new Y();
        Y y1 = (Y)x1;   // Works

        X x2 = new X();
        Y y2 = (Y)x2;   // InvalidCastException
    }
}

唯一的方法是覆盖转换运算符,它将在内部创建派生类的新实例,并将旧父实例中的所有字段复制到新派生的实例。

实体框架需要完全相同的方法。如果您从User实体开始,现在要将其推广到Employer实体,则必须删除旧用户并创建新的Employer

答案 1 :(得分:0)

假设您的Employer实体只有可以为空的属性,那么可以转到数据库中的表并将Discriminator从User更改为Employer。所有关系都将保留。并且可以做相反的事情。