在尝试使用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')
答案 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并查找方法,以实现上述描述。