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

发布于 2024-12-02 19:16:00 字数 1947 浏览 2 评论 0原文

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

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 持久化时,我该如何向下转型?

I have a project where I've defined in EF an Employer as a derived class of User. In my process I create a user without knowing whether it will eventually be an employer (or other kinds of users) and later I need to convert it. At first I tried (Intellisense indicated an explicit conversion exists):

Employer e = (Employer) GetUser();

but at runtime I got:

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

so I tried to write a converter:

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

but I get the error:

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

fine. I then overloaded the constructor for Employer like this:

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

and figured I could then just do:

Employer e = new Employer(GetUser());

but when I run it I get the error:

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

as a last resort I tried writing this:

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

... GetUser() returns an object of type User which does not offer the .Cast<> so I used a direct query to get there... but I still get the casting of dynamic proxy objects exception.

so my question is: how can I downcast when the object has persistence through EF?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦中的蝴蝶 2024-12-09 19:16:00

这是不可能的。您必须始终使用最终类型。一旦您将其创建为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

It is not possible. You must always use final type. Once you create it as a User, EF will never allow you changing it to a derived entity type.

Btw. it is also not possible with object oriented approach as well. You cannot cast instance of parent class to the instance of derived class (unless it really is instance of derived class) - it will throw exception at runtime. Very simple example to reproduce the issue:

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
    }
}

The only way to do that is overriding conversion operator which will internally create a new instance of derived class and copy all fields from the old parent instance to that new derived one.

Exactly the same approach is needed with entity framework. If you started with User entity and now you want to promote it to Employer entity you must delete old user and create new Employer.

扶醉桌前 2024-12-09 19:16:00

假设您的雇主实体仅具有可为空的属性,则可以转到数据库中的表并将鉴别器从用户更改为雇主。所有关系都将保留。而且也可以做相反的事情。

Supose that your Employer entity has only nullable properties then it is possible to go to the table at the database and change the Discriminator from User to Employer. All relationships will be kept. And also it is possible to do the opposite.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文