我在尝试使用教义单表继承时有一个很大的问题。
我有一个Division
实体,该实体代表地理区域(城市,县,国家,地区或任何特定国家/地区的行政部门)。为了满足我的应用需求,我需要特别识别具有City
实体的城市。我认为,城市是世界上广泛共享的行政领域,这是有道理的。
这是我基本上是想要的:
class Division {
/** @var boolean */
protected $city;
}
class City extends Division {
/** @var boolean */
protected $city = true;
}
两个是共享同一表的学说实体。
使用存储库,我希望能够获得此行为:
// 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"));
我已经与歧视者一起玩了很多,但是由于歧视者迫使我为部门实体做出独特的选择(因此,查询总是会得到city IN ('0')
),因此找不到一种方法来获得这一结果。我什至尝试创建一个" LoadClassMetadata"事件的侦听器,以覆盖元数据,但它会损坏很多东西。
在提出"为什么"问题的情况下:类型,更准确的相关实体关系,特定的存储库(以及更好的di)...很多原因!
关于如何用学说重现这一点的任何想法?看起来很简单,以至于我发疯了!
[编辑]这是我按照评论中要求的(
)尝试的(一种)歧视词。
/**
* @ORMTable(name="divisions")
* @ORMInheritanceType("SINGLE_TABLE")
* @ORMEntity()
* @ORMDiscriminatorColumn(name="city", type="integer")
* @ORMDiscriminatorMap({
* 0 = "Division",
* 1 = "Division",
* 1 = "City"
* })
*/
abstract class AbstractDivision
您不能这样做。我们在学说文档中有@DiscriminatorMap
说明:
IncriminatorMap的关键是数据库值,值是类。
因此,如果您将两个类设置为数据库值,那么学说将如何返回将city=1
列作为城市或部门的行?
学说的工作方式:
/**
* @ORMTable(name="divisions")
* @ORMInheritanceType("SINGLE_TABLE")
* @ORMEntity()
* @ORMDiscriminatorColumn(name="city", type="integer")
* @ORMDiscriminatorMap({
* 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
编辑
我发现的关于您的问题和地雷工作的唯一区别是:我没有使用抽象类。因此,划分将具有所有注释,并且将删除摘要。
关于查询构建器中的过滤器,仅返回城市或部门。您应该添加"实例",例如:
//$qb as a QueryBuilder instance, to returns only instances of City
$qb->from('ApiBundleEntityGeographyDivision','d');
$qb->andWhere('d INSTANCE OF ApiBundleEntityGeographyCity');
您需要为子实体定义至少一个存储库,并覆盖Findall并找到方法以实现您上述内容。