在symfony 2.8应用程序中,我将以下类层次结构配置为单表继承:
parent: App\Entity\AbstractUser
child1: App\Entity\UserClient
child2: App\Entity\UserGuest
从上到下的每个类还具有与App \ Entity \ Profile类的oneToOne关系。
基于上述情况,我在连接用户表的个人资料表上进行了本机查询。 目的是在一次查询中获得个人资料数据和相关的用户数据。
它确实工作了一段时间,但是在某些时候停止了工作。可能在学说捆绑更新之后。
现在,我下面的代码引发以下异常:The provided class "App\Entity\AbstractUser" is abstract, and can not be instantiated
。
我该怎么做才能使其再次正常工作?
这是我的代码:
$rsm = new ResultSetMapping;
$rsm->addEntityResult('App\Entity\AbstractUser', 'br');
$rsm->addFieldResult('br', 'user_id', 'id');
$sql = "
SELECT
rsa.id AS profile_id,
br.id AS user_id
FROM profiles rsa
LEFT OUTER JOIN users br ON rsa.id = br.profile_id
";
try {
$query = $this->_em->createNativeQuery($sql, $rsm);
$results = $query->getResult();
} catch (\Exception $e) {
throw $e;
}
这里是学说的定义:
// Resources/config/doctrine/AbstractUser.orm.yml
App\Entity\AbstractUser:
type: entity
table: users
inheritanceType: SINGLE_TABLE
discriminatorColumn:
name: type
type: string
length: 30
nullable: false
discriminatorMap:
client: App\Entity\UserClient
guest: App\Entity\UserGuest
fields:
id:
id: true
type: integer
generator:
strategy: AUTO
# oneToOne association
oneToOne:
profile:
targetEntity: App\Entity\Profile
cascade: ['persist','remove']
joinColumn:
name: profile_id
referencedColumnName: id
nullable: false
unique: false
// Resources/config/doctrine/UserClient.orm.yml
App\Entity\UserClient:
type: entity
// Resources/config/doctrine/UserGuest.orm.yml
App\Entity\UserGuest:
type: entity
// Resources/config/doctrine/Profile.orm.yml
App\Entity\Profile:
type: entity
table: profiles
fields:
id:
id: true
type: integer
generator:
strategy: AUTO
答案 0 :(得分:0)
您应该使用以下任一 :
两个here上的信息
这类似于PHP的抽象类。您无法实例化此类。因此,这是必须扩展为适当内容的一类。因此,您可以:
这将为您提供一些东西:
/**
* @ORM\MappedSuperclass
*/
abstract class AbstractEntity
{
/**
* @var int
* @ORM\Id
* @ORM\Column(name="id", type="integer", options={"unsigned":true})
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
// getter / setter
}
此用例显示了我自己项目中所有实体的通用标识符的用法。它还提供了一个简单的切入点,以验证特定实体是在我自己的项目中还是由供应商提供,请执行以下操作:
if ($entity instanceof AbstractEntity) { ... }
现在,让我们在表继承中使用MappedSuperclass。在此示例中,我们将采用JOINED
策略,但请随意使用最适合您的需求。
您有3个类,其中2个是可实例化的:
两者都来自:AbstractUser
现在,假设“来宾”是最受限制的用户,我们将首先创建该用户:
/**
* @ORM\Entity
* @ORM\Table(name="user_guests")
*/
class Guest extends AbstractEntity
{
/**
* @var string
* @ORM\Column(name="display_name", type="string", length=255, nullable=false)
*/
protected $displayName;
/**
* @var string
* @ORM\Column(name="email", type="string", length=255, nullable=false, unique=true)
*/
protected $email;
/**
* @var string
* @ORM\Column(name="password", type="text", nullable=false)
*/
protected $password;
// getters / setters
}
到目前为止很好。
现在,我们需要创建“客户端”。客户应具有:
前3个与Guest相同。因此,扩展Guest可能是明智的。每种用户类型的其他内容(例如功能)是否相同?如:
如果这些用例中的很多都是相同的,那么使用表继承就很可靠。因此,更新来宾注释,如下所示:
/**
* @ORM\Entity
* @ORM\Table(name="user_guests")
*
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
*/
class Guest extends AbstractEntity { ... }
注意 :我们不声明一个DiscriminatorMap
。教义将为我们解决这个问题。 Per the docs:
如果未提供区分图,则该图将自动生成。自动生成的鉴别符映射包含每个类的小写缩写名称作为键。
下一步,创建客户端:
/**
* @ORM\Entity
* @ORM\Table(name="user_clients")
*/
class Client extends Guest
{
/**
* @var string
* @ORM\Column(name="client_id", type="string", length=50, nullable=false)
*/
protected $clientId;
// getters / setters
}
例如,Doctrine为这2个生成的SQL是:
CREATE TABLE user_guests
(
id INT UNSIGNED AUTO_INCREMENT NOT NULL,
display_name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
password LONGTEXT NOT NULL,
discr VARCHAR(255) NOT NULL,
UNIQUE INDEX UNIQ_2843A78FE7927C74 (email),
PRIMARY KEY (id)
) DEFAULT CHARACTER SET utf8
COLLATE utf8_unicode_ci
ENGINE = InnoDB;
CREATE TABLE user_clients
(
id INT UNSIGNED NOT NULL,
client_id VARCHAR(50) NOT NULL,
PRIMARY KEY (id)
) DEFAULT CHARACTER SET utf8
COLLATE utf8_unicode_ci
ENGINE = InnoDB;
ALTER TABLE user_clients
ADD CONSTRAINT FK_58C5307EBF396750 FOREIGN KEY (id) REFERENCES user_guests (id) ON DELETE CASCADE;
直观显示,即:
现在,您还可以非常轻松地添加个人资料实体。您只需通过OneToOne bi-directional关系将其添加到Guest用户即可。
因此,添加到您的访客:
// other properties
/**
* @var Profile
* @ORM\OneToOne(targetEntity="Profile", cascade={"persist", "remove"}, fetch="EAGER", inversedBy="Guest")
* @ORM\JoinColumn(name="profile_id", referencedColumnName="id")
*/
protected $profile;
// getter / setter
但是,在这一点上,您可能希望考虑将“来宾”重命名为普通的“用户”,因为将来将其用于名称可能会减少混乱。 “用户”通常已经是一个非常有限的成员,类似于来宾(区别通常是“来宾” 不是注册用户,而用户是)。
现在您可以轻松地做到:
$profile->getGuest() // or ->getUser() if you renamed
// Returns instance of Guest (might be child instance: Client)
$guest->getProfile() // returns Profile
$client->getProfile() // returns Profile
$user = new Guest();
$user instanceof Guest ? true : false; // true
$user instanceof Client ? true : false; // false
$user = new Client();
$user instanceof Guest ? true : false; // true
$user instanceof Client ? true : false; // true