【问题标题】:Silverstripe: Many to many relation to same classSilverstripe:与同一类的多对多关系
【发布时间】:2014-07-02 03:03:58
【问题描述】:

我有一个班级“表演”,每个表演都可以作为推荐链接到其他表演。经过一些试验和错误后,我使用 ORM 得到了一些半成品:

public static $many_many = array(
    'Recommendations'       => 'Performance'
);

public static $belongs_many_many = array(
    'Recommendations'       => 'Performance'
);

上面让我指定建议,但在正常的多对多(两个类之间)中,相反的关系也是可用的。这里不是。关于如何在“性能”类上显示逆关系而不创建逆多对多并在此处手动插入逆关系的任何线索?

更新(2014 年 5 月 22 日):目前我得出的结论是,对于这个问题没有现成的解决方案。我根据@FinBoWa 的解决方案制作了以下最小示例,它显示了“未找到 Degree.InterestingDegreesReversed (Degree) 的逆分量”:

class Degree extends DataObject {

    private static $db = array(
        "Name"  => "Varchar(255)",
    );

    private static $many_many = array(
        'InterestingDegrees' => 'Degree'
    );

    private static $belongs_many_many = array(
        'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
    );

}

class DegreeAdmin extends ModelAdmin {
    public static $managed_models       = array('Degree'); 
    static $url_segment                 = 'degrees'; 
    static $menu_title                  = 'Degrees';
}

我也尝试了@g4b0 的解决方案,但它有一个严重的缺点,它没有在管理员中显示反向关系。现在我正在使用他的解决方案,但这并不是问题的真正解决方案。因此,我暂时不会接受答案...

【问题讨论】:

  • 您找到真正的解决方案了吗?我有同样的问题
  • 不,对不起...我解决了它...

标签: orm many-to-many silverstripe


【解决方案1】:

您必须为 many_many 和 belongs_many_many 指定两个不同的名称,以便您可以访问它们。例如:

public static $many_many = array(
    'RelatedRecommendations' => 'Performance'
);

public static $belongs_many_many = array(
    'Recommendations'        => 'Performance'
);

【讨论】:

  • 感谢您的回答!但是,将这两个添加到编辑屏幕中的两个选项卡中,似乎没有关系。 IE。添加相关推荐时,不会添加推荐。
  • 上面的代码对我有用,如果我将相关推荐 (A) 添加到现有性能 (B) 中,那么我可以在 A 的推荐中看到 B。只需尝试在推荐和相关推荐中循环模板。我还建议您通过 removeByName 功能删除 Recommendations 选项卡。
  • 你说,它以编程方式工作。好的,我明天检查一下。但是,我需要两个选项卡,因为关系不是对称的。关于如何做到这一点的任何线索?
  • 顺便问一下,ORM 应该如何知道如何将两者联系起来?
  • 试试吧。在 B 中,您将在 RelatedRecomendations 选项卡中看到 A,而在 B 中,您将在 Recomendation 选项卡中看到 A。您可以选择是否将两个选项卡都留在后端,或者删除其中一个。在前端,它将按预期工作。
【解决方案2】:

您应该能够在关系中使用点符号。

我们的一个项目有学位,我们想用同一个类来关联有趣的学位:

private static $many_many = array(
    'InterestingDegrees' => 'Degree'
);

private static $belongs_many_many = array(
    'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
);

如果您在关联站点树时手动添加编辑器,这将有效。

但是如果您使用模型管理员,则必须手动声明字段,否则您会出错。因此,如果您使用的是模型管理员,那么一个工作示例是:

class Degree extends DataObject {

    private static $db = array(
        "Name"  => "Varchar(255)",
    );

    private static $many_many = array(
        'InterestingDegrees' => 'Degree'
    );

    private static $belongs_many_many = array(
        'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
    );

    public function getCMSFields() {

        $fields =  new FieldList();

        $fields->add(new TextField("Name"));

        // dont show the field untill we have something to relate to 
        if($this->ID){
            //Interesting degrees
            $gfc = GridFieldConfig_RelationEditor::create();
            //Remove add and edit features
            $gfc->removeComponentsByType('GridFieldAddNewButton');
            $gfc->removeComponentsByType('GridFieldEditButton');
            $gf = new GridField('InterestingDegrees', null, $this->InterestingDegrees(), $gfc);
            $fields->add($gf);
        }
        return $fields;
    }
}

class DegreeAdmin extends ModelAdmin {
    public static $managed_models       = array('Degree'); 
    static $url_segment                 = 'degrees'; 
    static $menu_title                  = 'Degrees';
}

【讨论】:

  • 谢谢...我已经尝试过这个解决方案,但它导致了一个错误:Performance.RecommendationsReversed 的反向分量未找到(性能)
  • 这绝对适用于 3.1.4,因此您必须在不同版本上运行,或者在使用它后忽略运行 dev build。
  • 这绝对不适用于 3.1.4 和 3.1.5。我做了一个最小的对象,它给出了同样的错误信息。但也许这是因为我没有使用正常的页面结构。我只使用 DataObjects:class Degree extends DataObject
  • 我们的代码来自生产代码,它绝对有效!我会看看还有什么其他的吗
  • 啊!我认为您依靠模型管理员自动生成编辑器,因此它本身的关系不是问题,但自动编辑器生成会导致问题!在我们的例子中,我们使用的是 sitetree,它不会尝试自动添加编辑器。我会修改我的答案以包含我们使用的编辑器
【解决方案3】:

我已经经历了这两个想法,这就是我为我正在从事的项目提出的想法(我正在使用Brand 模型)。 这受到两种解决方案的启发,我要添加的唯一附加项是 onAfterWrite 方法。在那里,我只是遍历所有品牌,然后添加另一边。

这需要仅通过Brands 选项卡编辑所有品牌。另一个应该在getCMSFields 中删除,如下所示:$fields->removeByName('RelatedBrands');。

<?php
class Brand extends DataObject {
    private static $many_many = [
        'Brands' => 'Brand' //part 1 of brand-brand relation
    ];

    private static $belongs_many_many = [
        'RelatedBrands' => 'Brand' //part 2 of brand-brand relation
    ];

    public function onAfterWrite() {
        parent::onAfterWrite();

        foreach ($this->Brands() as $brand) {
            $this->RelatedBrands()->add($brand);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 2019-10-15
    • 1970-01-01
    • 2018-03-16
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多