如何处理不同实体类别的不同实体属性


How to handle different Entity-Properties for different Entity-Categories

我正面临一个问题,这可能是放在programmers.stackexchange.com,太,但因为它是相当绑定到Doctrine和ZF2,我选择把它放在这里。让我给你介绍一下我的场景:

  • 我有一个应用程序,用户发布实体(BaseEntity)。
  • BaseEntity具有$cagetory
  • 属性
  • 根据$category,实体必须有额外的属性

Ab simple示例:

class BaseEntity {
    protected $id;
    protected $title;
    protected $description;
}
class MovieEntity {
    protected $id;
    protected $title;
    protected $description;
    protected $airingDateStart; // new property
    protected $airingDateEnd;   // new property
}

现在我可以很容易地做一个两步公式,其中用户首先选择他的类别,并取决于EntityClass将被选择-但我不能有。但这并不好,因为如果用户在BaseEntity -类别中放置了一个电影,然后想要将实体更改为MovieEntity呢?所以这个想法并不是一个安全的选择。

附加要求(使事情更复杂)

  • 类别和实体必须由原则
  • 控制
  • 每个Category通过单个Module提供给应用程序
  • 模块需要在不需要太多配置的情况下放置到应用程序中(最多一个DB-Query来填充CategoryTable)

我做了什么

首先,我选择使用doctrine功能单表继承运行。这使我能够轻松地做MovieEntity extends BaseEntity之类的事情,并像向数据库添加新实体一样发挥作用。但是主要的问题仍然存在:如果用户改变Category,它会改变EntityClass,这几乎是一个No-Go。

我的意思是,是的,我可以用我现在的方式做事情,在更改类别时手动修改DiscriminatorColumn,但那太脏了。

另一种替代方法是,在更改类别的事件中,将创建一个新的实体,而旧的实体将被销毁,但这也感觉有点脏。

总而言之,我觉得我走错方向了。可能有一种我不知道的发展模式,使我所有的努力看起来像浪费,事情最终变得超级容易,但似乎我忽略了一些东西。

也许得到一个更接近我的想法,你可以看看我在GitHub上的应用程序:

  • DuitMarketplace -这是带有基本类别,所有控制器等的主要应用程序。ItemController#editAction()可能会提供更多的线索,我打算如何自动制造一些东西。
  • DuitMarketplaceItemVehicle -一个被放入主应用
  • 的类别

提前感谢我可能得到的所有反馈。我完全意识到这个问题可能是存在于SO和程序员之间的边界。但是我还是选择把它放在这里

如果我对您的情况理解正确的话,听起来您最好避免在Thing上继承,而是将特定于类别的属性作为Things和Categories之间关系的属性。

这样的架构呢:

<?php
class Category {
    protected $id;
    protected $title;
    protected $things; //@ManyToOne(targetEntity="ThingCategory")
}
class Thing {
    protected $id;
    protected $title;
    protected $description;
    protected $category; //@ManyToOne(targetEntity="ThingCategory")
}    
/**
 * Use [Single|Class]-Table Inheritence to model subject-category attributes.
 * 
 * ThingCategory is just a base class.  Modules provide concrete subclasses
 * that encapsulate category-specific attributes.
 */
class ThingCategory {
    protected $id; //surrogate key, not strictly necessary
    protected $thing; //@ManyToOne(targetEntity="Thing")
    protected $category //@ManyToOne(targetEntity="Category")
}
class ThingMovieCategory extends ThingCategory{
    protected $airingStartDate;
    protected $airingEndDate;
}
class ThingCarCategory extends ThingCategory {
    protected $horespower;
    protected $numberOfDoors;
    protected $color;
}

所以,现在事物可以通过替换与之关联的ThingCategory实体在类别之间移动。事物的身份从未改变,改变的只是它与范畴的关系。必须包含在该类别中的属性是ThingCategory关系实体的属性,而不是Thing本身的属性。

编辑:您可能遇到的问题是,当子类化实体时,没有记录修改标识符映射的方法。不幸的副作用是,您的基本模块必须了解每个可能的模块。但这可能不是一个大问题。如果是的话,我相信可以通过让每个模块操作基实体的ClassMetaData来避免这种情况,但我从来没有真正让它工作。

你的问题是这句话"但主要问题仍然是:如果用户改变Category,它会改变EntityClass,这几乎是一个No-Go。"

一个类别实际上不会改变,它会被删除,并被一个新的类别所取代。因此,在代码中反映这一点,创建一个新实体,持久化它,更新所有指向新实体的引用,然后删除旧实体。