使用这些类,您如何将"Person"的记录更改为"Employee".
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
*/
class Person
{
// ...
}
/**
* @Entity
*/
class Employee extends Person
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
我尝试更改鉴别器列的值,但我无法访问它.我还尝试创建一个'Employee'实例并手动复制数据,但这不适用于自动递增id.它只是作为新记录添加而不是更新现有记录.
我是否需要编写自定义的SQL查询,或者我在做其他根本错误的事情?
假设我在模型中有2个类:User(映射到USERS表)和PrivilegedUser(继承User,其他信息存储在PRIVILEGEDUSERS表中).
现在,我在USERS(和User的实例)中有一行,需要将该用户转换为PrivilegedUser(即在PRIVILEGEDUSERS中创建具有相同Id的记录).有没有办法在没有删除/插入的情况下执行此操作?
问题是您在模型中没有PRIVILEGEDUSERS表示,因此您不能仅创建PrivilegedUser的那部分.
这只是一个例子.除普通用户属性外,PrivilegedUser可能还有一些折扣或个人经理或其他任何东西.同时,无论具体的用户类型如何,还有其他表需要引用用户.我已经使用Table-per-Type继承模式实现了它.在数据库级别,将用户从一种类型转换为另一种类型非常简单(您只需要从扩展表中插入或删除记录).但在EF中,您只有UserSet,它存储User和PrivilegedUser对象.这就是为什么我要问是可以用PrivilegedUser 替换现有的 User对象来保留现有的Id并且不从USERS表中删除记录.
在我的项目中,我有几个类表继承如下:
namespace MyProject\Model;
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
*/
class Person
{
// ...
}
/** @Entity */
class Employee extends Person
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
我有一个方法,它根据具有公共getter的字段将实体转换为数组.这里的问题是我丢失了数组中的继承信息,因为鉴别器值没有存储在字段中.
所以我尝试的是以下内容,希望教义会自动设置$disc:
class Person
{
// can I automatically populate this field with 'person' or 'employee'?
protected $discr;
public function getDiscr() { return $this->discr; }
public function setDiscr($disc) { $this->discr; }
// ...
}
Run Code Online (Sandbox Code Playgroud)
有没有办法在学说中使这项工作?或者我需要在实体到数组方法中读取类元数据?
在对域类进行建模时,我发现Entity Framework允许您对继承关系进行建模,但不支持将基类型实例提升为其派生类型,即将数据库中现有的Person行更改为派生自Person的Employee.
显然,我并不是第一个对此感到疑惑的人,因为这个问题已经多次在Stack Overflow上被提出并回答(例如,见此处和此处).
如这些答案中所示,实体框架不支持这一点,因为在面向对象编程中不允许这样做:创建实例后,您无法更改其运行时类型.
很公平,从技术角度来看,我可以理解,一旦为一个对象分配了一个单独的内存块,之后添加一些额外的字节来保存派生类型的字段可能需要重新分配整个内存块,并且结果,意味着对象的指针现在已经改变,这反过来又引入了更多的问题.所以我觉得这很难实现,因此在C#中不受支持.
但是,除了从技术组件,答案(和这里也看到第1页最后一段)也似乎暗示着它被认为是不好的设计,当你想改变一个对象的运行时类型,说你不应该需要这种类型改变,而应该使用组合来代替这些情况.
坦率地说,我不明白为什么 - 我说完全有效的想要以与使用Person实例相同的方式工作Employee实例(即通过从Person继承Employee),即使在某个时间点a人员将被雇用为员工,或者员工退出并再次成为人员.
从概念上讲,我没有看到任何错误?
任何人都可以向我解释这个吗?
- 编辑,澄清,为什么这被认为是糟糕的设计:
public class Person
{
public string Name { get; set; }
}
public class Employee: Person
{
public int EmployeeNr { get; set; }
public decimal Salary { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
......但这不是?
public class Person
{
public string Name { get; set; }
public EmployeeInfo EmployeeInfo { get; set; }
}
public class EmployeeInfo
{ …Run Code Online (Sandbox Code Playgroud) 我有一个简单的层次结构
public abstract class CommunicationSupport
{
public SupportTypeEnum Type { get; set; }
public Country Origin { get; set; } // National or Foreign support
}
public class TelecomSupport : CommunicationSupport
{
public string Number { get; set; }
}
public class PostalSupport : CommunicationSupport
{
public Address Address { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我计划为我的数据库使用Table-per-type层次结构.因此将创建3个表,一个基数和两个子项使用与基础相同的PK.
我的问题是我希望能够通过更改它的类型来更新CommunicationSupport.假设我创建了一个TelecomSupport,将其保存,然后将其类型更改为PostalSupport并再次保存(更新).我期望的结果是EF保持相同的基本记录(CommunicationSupport Id),但删除TelecomSupport表中的记录并在PostalSupport中创建一个新记录.因此,TelecomSupport和PostalSupport是独家的,不能共享相同的基础CommunicationSupport.
我如何使用EntityFramework 5来做到这一点?
谢谢你的帮助!
我已经找到了一些有关这方面的信息,但还不足以让我理解这种情况的最佳实践.我有你的典型TPH设置与抽象基类"公司".我有几个孩子"小公司","大公司"等继承自公司.实际上,我实际上对公司有不同的现实分类,但我试图在这个例子中保持简单.在根据TPH的数据库中,我有一个具有FirmTypeId列(int)的Firm表,用于区分所有这些类型.一切都很好,除了我要求允许用户将一种类型的公司改为另一种.例如,用户在添加公司时可能会犯错,并希望将其从Big Firm更改为Small Firm.因为实体框架不允许将区分数据库列暴露为属性,所以我不相信有一种方法可以通过EF将一种类型更改为另一种类型.如果我错了,请纠正我.我看到它的方式我有两个选择:
我看过一篇文章,人们认为OOP的一个原则是实例不能改变它们的类型.虽然这对我来说很有意义,但我似乎无法连接点.如果我们遵循这个规则,那么唯一一次使用任何类型的继承(TPH/TPT)就是确定一种类型永远不会转换为另一种类型.因此,小公司永远不会成为一家大公司.我看到应该使用构图的建议.即使它对我来说没有意义(意思是我没有看到公司如何拥有一家大公司,对我来说,一家大公司就是一家公司),我可以看到如果数据存在,如何在EF中建模组合.多个表.但是,在我在数据库中有一个表的情况下,它似乎是TPH或我在上面#1和#2中描述的内容.