Doctrine单表继承保留findAll

时间:2016-12-26 18:36:13

标签: php symfony doctrine-orm doctrine

在尝试使用Doctrine Single Table Inheritance时,我遇到了一个很大的问题。

我有一个Division实体,代表地理区域(城市,县,国家/地区或任何特定国家/地区的行政区划)。对于我的应用程序需求,我需要专门识别具有City实体的城市。在我看来,城市是世界上广泛分享的行政区域,这是有道理的。

以下是基本想要的内容:

class Division {
    /** @var boolean */
    protected $city;
}

class City extends Division {
    /** @var boolean */
    protected $city = true;
}

两者都是共享同一个表的Doctrine实体。

使用存储库,我希望能够获得此行为:

// return counties, regions, AND cities but all mapped to Division class
$divisionsRepositories->findAll();

// return only cities, mapped to City class
$citiesRepositories->findAll();

// if id #12 is a division with $city = false, returns null
$citiesRepositories->find(12);

// persist to divisions table a row with city = 1
$citiesRepositories->persist(new City("Paris"));

我与鉴别家玩了很多,并且无法找到获得此结果的方法,因为鉴别器迫使我为Division实体做出唯一的选择(所以查询总是得到{{1} })。我甚至试图创建一个" loadClassMetadata"事件监听器覆盖元数据但它打破了很多东西。

如果问题"为什么"被问到:typehinting,更准确的相关实体关系,特定的存储库(以及更好的DI)......很多原因!

有关如何使用Doctrine重现这一点的任何想法?它看起来很简单,让我发疯了!

[编辑] 这是我在评论中要求尝试的鉴别器地图之一(

city IN ('0')

2 个答案:

答案 0 :(得分:2)

你不能这样做。我们在doctrine documentation中有@DiscriminatorMap解释:

  

DiscriminatorMap上的键是数据库值,值是类。

因此,如果您将两个Classes设置为数据库值,那么doctrine将如何返回将city=1列作为城市或分部的行?

学说如何运作:

/**
 * @ORM\Table(name="divisions")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\Entity()
 * @ORM\DiscriminatorColumn(name="city", type="integer")
 * @ORM\DiscriminatorMap({
 *     0 = "Division",
 *     1 = "City"
 * })
 */
abstract class Division

// return Division and it subclasses but all mapped to their repectives classes
$divisionsRepositories->findAll();

// return only cities, mapped to City class
$citiesRepositories->findAll();

// if id #12 is a Division instance (city = false), returns null
$citiesRepositories->find(12);

// persist to divisions table a row with city = 1
$citiesRepositories->persist(new City("Paris"));

所以几乎每件事都像你期望的那样。第一种情况,$divisionsRepositories->findAll()这是唯一的问题。但如果你仔细观察是因为:

//if $divisions returns for instance an array [City, Division]
$divisions = $divisionsRepositories->findAll();

// City instance
$city =  $division[0];

// Division instance
$division = $division[1];

echo $city instanceof City; // true, outputs 1
echo $city instanceof Division; // true, outputs also 1

echo $division instanceof City; // false, outputs empty
echo $division instanceof Division; // true, outputs 1

修改

我发现的关于你的问题和我的工作的唯一区别是:我没有使用抽象类。因此,Division将拥有所有注释,AbstractdDivision将被删除。

关于按实例查询构建器中的过滤器,仅返回City或Division。你应该添加' INSTANCE OF'如下所示:

 //$qb as a QueryBuilder instance, to returns only instances of City
 $qb->from('\ApiBundle\Entity\Geography\Division','d');
 $qb->andWhere('d INSTANCE OF \ApiBundle\Entity\Geography\City');

答案 1 :(得分:0)

您需要为子实体定义至少一个repository并覆盖findAll并查找方法,以实现上述描述。