mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
* Make Column::$type, Column::$nullable and JoinColumn::$nullable nullable by default * Add tests for mapped typed properties (type and nullable) * Fix Yaml driver tests and remove driver exceptions thrown too early * Fix PHP driver tests * Fix static PHP driver tests * Fix XML driver tests * Coding Standards * Deprecate unused MappingException method * Add manyToOne test and check nullable at the right place * Coding Standards * Bugfix: Temporarily change association join columns in CascadeRemoveOrderTest to circumvent new CommitOrderCalculator bug. * phpcs Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
This commit is contained in:
@@ -541,7 +541,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" />
|
||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
@@ -559,7 +559,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||
|
||||
@@ -1758,6 +1758,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
[
|
||||
'name' => $this->namingStrategy->joinColumnName($mapping['fieldName'], $this->name),
|
||||
'referencedColumnName' => $this->namingStrategy->referenceColumnName(),
|
||||
'nullable' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -1775,6 +1776,10 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
if (! isset($joinColumn['nullable'])) {
|
||||
$joinColumn['nullable'] = true;
|
||||
}
|
||||
|
||||
if (empty($joinColumn['name'])) {
|
||||
$joinColumn['name'] = $this->namingStrategy->joinColumnName($mapping['fieldName'], $this->name);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ final class Column implements Annotation
|
||||
public $name;
|
||||
|
||||
/** @var mixed */
|
||||
public $type = 'string';
|
||||
public $type;
|
||||
|
||||
/** @var int */
|
||||
public $length;
|
||||
@@ -57,8 +57,8 @@ final class Column implements Annotation
|
||||
/** @var bool */
|
||||
public $unique = false;
|
||||
|
||||
/** @var bool */
|
||||
public $nullable = false;
|
||||
/** @var bool|null */
|
||||
public $nullable;
|
||||
|
||||
/** @var array<string,mixed> */
|
||||
public $options = [];
|
||||
@@ -71,12 +71,12 @@ final class Column implements Annotation
|
||||
*/
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
string $type = 'string',
|
||||
?string $type = null,
|
||||
?int $length = null,
|
||||
?int $precision = null,
|
||||
?int $scale = null,
|
||||
bool $unique = false,
|
||||
bool $nullable = false,
|
||||
?bool $nullable = null,
|
||||
array $options = [],
|
||||
?string $columnDefinition = null
|
||||
) {
|
||||
|
||||
@@ -370,10 +370,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
|
||||
// @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
|
||||
$columnAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Column::class);
|
||||
if ($columnAnnot) {
|
||||
if ($columnAnnot->type === null) {
|
||||
throw MappingException::propertyTypeIsRequired($className, $property->getName());
|
||||
}
|
||||
|
||||
$mapping = $this->columnToArray($property->getName(), $columnAnnot);
|
||||
|
||||
$idAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Id::class);
|
||||
|
||||
@@ -258,10 +258,6 @@ class AttributeDriver extends AnnotationDriver
|
||||
$embeddedAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Embedded::class);
|
||||
|
||||
if ($columnAttribute !== null) {
|
||||
if ($columnAttribute->type === null) {
|
||||
throw MappingException::propertyTypeIsRequired($className, $property->getName());
|
||||
}
|
||||
|
||||
$mapping = $this->columnToArray($property->getName(), $columnAttribute);
|
||||
|
||||
if ($this->reader->getPropertyAnnotation($property, Mapping\Id::class)) {
|
||||
|
||||
@@ -409,9 +409,12 @@ class XmlDriver extends FileDriver
|
||||
foreach ($xmlRoot->{'one-to-one'} as $oneToOneElement) {
|
||||
$mapping = [
|
||||
'fieldName' => (string) $oneToOneElement['field'],
|
||||
'targetEntity' => (string) $oneToOneElement['target-entity'],
|
||||
];
|
||||
|
||||
if (isset($oneToOneElement['target-entity'])) {
|
||||
$mapping['targetEntity'] = (string) $oneToOneElement['target-entity'];
|
||||
}
|
||||
|
||||
if (isset($associationIds[$mapping['fieldName']])) {
|
||||
$mapping['id'] = true;
|
||||
}
|
||||
@@ -462,10 +465,13 @@ class XmlDriver extends FileDriver
|
||||
foreach ($xmlRoot->{'one-to-many'} as $oneToManyElement) {
|
||||
$mapping = [
|
||||
'fieldName' => (string) $oneToManyElement['field'],
|
||||
'targetEntity' => (string) $oneToManyElement['target-entity'],
|
||||
'mappedBy' => (string) $oneToManyElement['mapped-by'],
|
||||
];
|
||||
|
||||
if (isset($oneToManyElement['target-entity'])) {
|
||||
$mapping['targetEntity'] = (string) $oneToManyElement['target-entity'];
|
||||
}
|
||||
|
||||
if (isset($oneToManyElement['fetch'])) {
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $oneToManyElement['fetch']);
|
||||
}
|
||||
@@ -509,9 +515,12 @@ class XmlDriver extends FileDriver
|
||||
foreach ($xmlRoot->{'many-to-one'} as $manyToOneElement) {
|
||||
$mapping = [
|
||||
'fieldName' => (string) $manyToOneElement['field'],
|
||||
'targetEntity' => (string) $manyToOneElement['target-entity'],
|
||||
];
|
||||
|
||||
if (isset($manyToOneElement['target-entity'])) {
|
||||
$mapping['targetEntity'] = (string) $manyToOneElement['target-entity'];
|
||||
}
|
||||
|
||||
if (isset($associationIds[$mapping['fieldName']])) {
|
||||
$mapping['id'] = true;
|
||||
}
|
||||
@@ -554,9 +563,12 @@ class XmlDriver extends FileDriver
|
||||
foreach ($xmlRoot->{'many-to-many'} as $manyToManyElement) {
|
||||
$mapping = [
|
||||
'fieldName' => (string) $manyToManyElement['field'],
|
||||
'targetEntity' => (string) $manyToManyElement['target-entity'],
|
||||
];
|
||||
|
||||
if (isset($manyToManyElement['target-entity'])) {
|
||||
$mapping['targetEntity'] = (string) $manyToManyElement['target-entity'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['fetch'])) {
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $manyToManyElement['fetch']);
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ class YamlDriver extends FileDriver
|
||||
foreach ($element['oneToOne'] as $name => $oneToOneElement) {
|
||||
$mapping = [
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $oneToOneElement['targetEntity'],
|
||||
'targetEntity' => $oneToOneElement['targetEntity'] ?? null,
|
||||
];
|
||||
|
||||
if (isset($associationIds[$mapping['fieldName']])) {
|
||||
@@ -515,7 +515,7 @@ class YamlDriver extends FileDriver
|
||||
foreach ($element['manyToOne'] as $name => $manyToOneElement) {
|
||||
$mapping = [
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $manyToOneElement['targetEntity'],
|
||||
'targetEntity' => $manyToOneElement['targetEntity'] ?? null,
|
||||
];
|
||||
|
||||
if (isset($associationIds[$mapping['fieldName']])) {
|
||||
|
||||
@@ -40,8 +40,8 @@ final class JoinColumn implements Annotation
|
||||
/** @var bool */
|
||||
public $unique = false;
|
||||
|
||||
/** @var bool */
|
||||
public $nullable = true;
|
||||
/** @var bool|null */
|
||||
public $nullable;
|
||||
|
||||
/** @var mixed */
|
||||
public $onDelete;
|
||||
@@ -60,7 +60,7 @@ final class JoinColumn implements Annotation
|
||||
?string $name = null,
|
||||
string $referencedColumnName = 'id',
|
||||
bool $unique = false,
|
||||
bool $nullable = true,
|
||||
?bool $nullable = null,
|
||||
$onDelete = null,
|
||||
?string $columnDefinition = null,
|
||||
?string $fieldName = null
|
||||
|
||||
@@ -52,7 +52,7 @@ final class ManyToOne implements Annotation
|
||||
* @param array<string> $cascade
|
||||
*/
|
||||
public function __construct(
|
||||
string $targetEntity,
|
||||
?string $targetEntity = null,
|
||||
?array $cascade = null,
|
||||
string $fetch = 'LAZY',
|
||||
?string $inversedBy = null
|
||||
|
||||
@@ -382,6 +382,8 @@ class MappingException extends ORMException
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2.9 no longer in use
|
||||
*
|
||||
* @param string $className
|
||||
* @param string $propertyName
|
||||
*
|
||||
|
||||
@@ -7,46 +7,129 @@ namespace Doctrine\Tests\Models\TypedProperties;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\Tests\Models\CMS\CmsEmail;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="cms_users_typed")
|
||||
*/
|
||||
#[ORM\Entity, ORM\Table(name: 'cms_users_typed')]
|
||||
class UserTyped
|
||||
{
|
||||
/**
|
||||
* @Id @Column
|
||||
* @GeneratedValue
|
||||
*/
|
||||
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
|
||||
public int $id;
|
||||
/** @Column(length=50) */
|
||||
#[ORM\Column(length: 50)]
|
||||
public ?string $status;
|
||||
|
||||
/** @Column(length=255, unique=true) */
|
||||
#[ORM\Column(length: 255, unique: true)]
|
||||
public string $username;
|
||||
|
||||
/** @Column */
|
||||
#[ORM\Column]
|
||||
public DateInterval $dateInterval;
|
||||
|
||||
/** @Column */
|
||||
#[ORM\Column]
|
||||
public DateTime $dateTime;
|
||||
|
||||
/** @Column */
|
||||
#[ORM\Column]
|
||||
public DateTimeImmutable $dateTimeImmutable;
|
||||
|
||||
/** @Column */
|
||||
#[ORM\Column]
|
||||
public array $array;
|
||||
|
||||
/** @Column */
|
||||
#[ORM\Column]
|
||||
public bool $boolean;
|
||||
|
||||
/** @Column */
|
||||
#[ORM\Column]
|
||||
public float $float;
|
||||
|
||||
/**
|
||||
* @OneToOne(cascade={"persist"}, orphanRemoval=true)
|
||||
* @JoinColumn
|
||||
*/
|
||||
#[ORM\OneToOne(cascade: ['persist'], orphanRemoval: true), ORM\JoinColumn]
|
||||
public CmsEmail $email;
|
||||
|
||||
/** @ManyToOne */
|
||||
#[ORM\ManyToOne]
|
||||
public ?CmsEmail $mainEmail;
|
||||
|
||||
public static function loadMetadata(ClassMetadataInfo $metadata): void
|
||||
{
|
||||
$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE);
|
||||
$metadata->setPrimaryTable(
|
||||
['name' => 'cms_users_typed']
|
||||
);
|
||||
|
||||
$metadata->mapField(
|
||||
[
|
||||
'id' => true,
|
||||
'fieldName' => 'id',
|
||||
]
|
||||
);
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
|
||||
$metadata->mapField(
|
||||
[
|
||||
'fieldName' => 'status',
|
||||
'length' => 50,
|
||||
]
|
||||
);
|
||||
$metadata->mapField(
|
||||
[
|
||||
'fieldName' => 'username',
|
||||
'length' => 255,
|
||||
'unique' => true,
|
||||
]
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'dateInterval']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'dateTime']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'dateTimeImmutable']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'array']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'boolean']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'float']
|
||||
);
|
||||
|
||||
$metadata->mapOneToOne(
|
||||
[
|
||||
'fieldName' => 'email',
|
||||
'cascade' =>
|
||||
[0 => 'persist'],
|
||||
'joinColumns' =>
|
||||
[
|
||||
0 =>
|
||||
[],
|
||||
],
|
||||
'orphanRemoval' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$metadata->mapManyToOne(
|
||||
['fieldName' => 'mainEmail']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ class CascadeRemoveOrderEntityG
|
||||
* targetEntity="Doctrine\Tests\ORM\Functional\CascadeRemoveOrderEntityO",
|
||||
* inversedBy="oneToMany"
|
||||
* )
|
||||
* @JoinColumn(nullable=true, onDelete="SET NULL")
|
||||
*/
|
||||
private $ownerO;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ use Doctrine\Persistence\Mapping\RuntimeReflectionService;
|
||||
use Doctrine\Tests\Models\Cache\City;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddress;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddressListener;
|
||||
use Doctrine\Tests\Models\CMS\CmsEmail;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\Company\CompanyContract;
|
||||
use Doctrine\Tests\Models\Company\CompanyContractListener;
|
||||
@@ -41,6 +42,7 @@ use Doctrine\Tests\Models\DDC889\DDC889Class;
|
||||
use Doctrine\Tests\Models\DDC889\DDC889Entity;
|
||||
use Doctrine\Tests\Models\DDC964\DDC964Admin;
|
||||
use Doctrine\Tests\Models\DDC964\DDC964Guest;
|
||||
use Doctrine\Tests\Models\TypedProperties\UserTyped;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
|
||||
use function assert;
|
||||
@@ -51,6 +53,7 @@ use function strpos;
|
||||
use function strtolower;
|
||||
|
||||
use const CASE_UPPER;
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
abstract class AbstractMappingDriverTest extends OrmTestCase
|
||||
{
|
||||
@@ -262,6 +265,46 @@ abstract class AbstractMappingDriverTest extends OrmTestCase
|
||||
return $class;
|
||||
}
|
||||
|
||||
public function testFieldIsNullableByType(): void
|
||||
{
|
||||
if (PHP_VERSION_ID < 70400) {
|
||||
$this->markTestSkipped('requies PHP 7.4');
|
||||
}
|
||||
|
||||
$class = $this->createClassMetadata(UserTyped::class);
|
||||
|
||||
// Explicit Nullable
|
||||
$this->assertTrue($class->isNullable('status'));
|
||||
|
||||
// Explicit Not Nullable
|
||||
$this->assertFalse($class->isNullable('username'));
|
||||
|
||||
// Join table Nullable
|
||||
$this->assertFalse($class->getAssociationMapping('email')['joinColumns'][0]['nullable']);
|
||||
$this->assertEquals(CmsEmail::class, $class->getAssociationMapping('email')['targetEntity']);
|
||||
|
||||
$this->assertTrue($class->getAssociationMapping('mainEmail')['joinColumns'][0]['nullable']);
|
||||
$this->assertEquals(CmsEmail::class, $class->getAssociationMapping('mainEmail')['targetEntity']);
|
||||
}
|
||||
|
||||
public function testFieldTypeFromReflection(): void
|
||||
{
|
||||
if (PHP_VERSION_ID < 70400) {
|
||||
$this->markTestSkipped('requies PHP 7.4');
|
||||
}
|
||||
|
||||
$class = $this->createClassMetadata(UserTyped::class);
|
||||
|
||||
$this->assertEquals('integer', $class->getTypeOfField('id'));
|
||||
$this->assertEquals('string', $class->getTypeOfField('username'));
|
||||
$this->assertEquals('dateinterval', $class->getTypeOfField('dateInterval'));
|
||||
$this->assertEquals('datetime', $class->getTypeOfField('dateTime'));
|
||||
$this->assertEquals('datetime_immutable', $class->getTypeOfField('dateTimeImmutable'));
|
||||
$this->assertEquals('json', $class->getTypeOfField('array'));
|
||||
$this->assertEquals('boolean', $class->getTypeOfField('boolean'));
|
||||
$this->assertEquals('float', $class->getTypeOfField('float'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testEntityTableNameAndInheritance
|
||||
*/
|
||||
|
||||
@@ -132,6 +132,10 @@ class ClassMetadataTest extends OrmTestCase
|
||||
$cm->mapOneToOne(['fieldName' => 'email', 'joinColumns' => [[]]]);
|
||||
$this->assertFalse($cm->getAssociationMapping('email')['joinColumns'][0]['nullable']);
|
||||
$this->assertEquals(CmsEmail::class, $cm->getAssociationMapping('email')['targetEntity']);
|
||||
|
||||
$cm->mapManyToOne(['fieldName' => 'mainEmail']);
|
||||
$this->assertTrue($cm->getAssociationMapping('mainEmail')['joinColumns'][0]['nullable']);
|
||||
$this->assertEquals(CmsEmail::class, $cm->getAssociationMapping('mainEmail')['targetEntity']);
|
||||
}
|
||||
|
||||
public function testFieldTypeFromReflection(): void
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
|
||||
$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE);
|
||||
$metadata->setPrimaryTable(
|
||||
['name' => 'cms_users_typed']
|
||||
);
|
||||
|
||||
$metadata->mapField(
|
||||
[
|
||||
'id' => true,
|
||||
'fieldName' => 'id',
|
||||
]
|
||||
);
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
|
||||
$metadata->mapField(
|
||||
[
|
||||
'fieldName' => 'status',
|
||||
'length' => 50,
|
||||
]
|
||||
);
|
||||
$metadata->mapField(
|
||||
[
|
||||
'fieldName' => 'username',
|
||||
'length' => 255,
|
||||
'unique' => true,
|
||||
]
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'dateInterval']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'dateTime']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'dateTimeImmutable']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'array']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'boolean']
|
||||
);
|
||||
$metadata->mapField(
|
||||
['fieldName' => 'float']
|
||||
);
|
||||
|
||||
$metadata->mapOneToOne(
|
||||
[
|
||||
'fieldName' => 'email',
|
||||
'cascade' => [0 => 'persist'],
|
||||
'joinColumns' => [[]],
|
||||
'orphanRemoval' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$metadata->mapManyToOne(
|
||||
['fieldName' => 'mainEmail']
|
||||
);
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\TypedProperties\UserTyped" table="cms_users_typed">
|
||||
<id name="id">
|
||||
<generator strategy="AUTO"/>
|
||||
</id>
|
||||
|
||||
<field name="status" length="50"/>
|
||||
<field name="username" length="255" unique="true"/>
|
||||
<field name="dateInterval"/>
|
||||
<field name="dateTime"/>
|
||||
<field name="dateTimeImmutable"/>
|
||||
<field name="array"/>
|
||||
<field name="boolean"/>
|
||||
<field name="float"/>
|
||||
|
||||
<one-to-one field="email" orphan-removal="true">
|
||||
<cascade><cascade-persist /></cascade>
|
||||
<join-column/>
|
||||
</one-to-one>
|
||||
|
||||
<many-to-one field="mainEmail"/>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
@@ -0,0 +1,26 @@
|
||||
Doctrine\Tests\Models\TypedProperties\UserTyped:
|
||||
type: entity
|
||||
table: cms_users_typed
|
||||
id:
|
||||
id:
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
status:
|
||||
length: 50
|
||||
username:
|
||||
length: 255
|
||||
unique: true
|
||||
dateInterval: ~
|
||||
dateTime: ~
|
||||
dateTimeImmutable: ~
|
||||
array: ~
|
||||
boolean: ~
|
||||
float: ~
|
||||
oneToOne:
|
||||
email:
|
||||
cascade: [ persist ]
|
||||
orphanRemoval: true
|
||||
joinColumn: []
|
||||
manyToOne:
|
||||
mainEmail: []
|
||||
Reference in New Issue
Block a user