以编程方式设置值时查询的字段索引不更新

Field index for queries not updating when value set programmatically

我的模块通过控制器创建自定义内容项:

   private ContentItem createContentItem()
    {
        // Add the field
        _contentDefinitionManager.AlterPartDefinition(
            "TestType",
            cfg => cfg
            .WithField(
                "NewField",
                f => f
                    .OfType(typeof(BooleanField).Name)
                    .WithDisplayName("New Field"))
            );

        // Not sure if this is needed
        _contentDefinitionManager.AlterTypeDefinition(
            "TestType",
            cfg => cfg
                .WithPart("TestType")
            );

        // Create new TestType item
        var newItem = _contentManager.New("TestType");
        _contentManager.Create(TestItem, VersionOptions.Published);

        // Set the added boolean field to true
        BooleanField newField = ((dynamic)newItem).TestType.NewField as BooleanField;
        newField.Value = true;

        // Set title (as date created, for convenience)
        var time = DateTime.Now.ToString("MM-dd-yyyy h:mm:ss tt", CultureInfo.InvariantCulture).Replace(':', '.');
        newItem.As<TitlePart>().Title = time;

        return newItem;
    }

此操作的最终结果是一个新的 TestType 项目,其字段设置为 true。查看仪表板中的内容项以及检查数据库中的 ContentItemVersionRecord 可确认值设置正确。

但是,查询似乎无法在以这种方式设置的字段上正常工作。我找到了记录 IntegerFieldIndexRecord,这是我假设投影用于填充查询结果页面的记录。对此,TestField 的值保持为 0(假),而不是 1(真)。

转到内容项编辑页面并单击 'save' 即可正确更新 IntegerFieldIndexRecord,这意味着该值现在已由查询获取。如何为以编程方式设置的字段值更新记录?

迁移的相关部分:

SchemaBuilder.CreateTable(typeof(TestTypePartRecord).Name, table => table
            .ContentPartRecord()
        );

        ContentDefinitionManager.AlterTypeDefinition(
            "TestType",
            cfg => cfg
                .DisplayedAs("Test Type")
                .WithPart(typeof(TitlePart).Name)
                .WithPart(typeof(ContainablePart).Name)
                .WithPart(typeof(CommonPart).Name)
                .WithPart(typeof(IdentityPart).Name)
            );

编辑:解决此问题的方法是在每次更改字段值时手动更改投影索引记录,使用此调用:

_fieldIndexService.Set(testResultItem.As<FieldIndexPart>(),
     "TestType", // Resolves as TestTypePart, which holds the field
     "newField",
     "", // Not sure why value name should be empty, but whatever
     true, // The value to be set goes here
     typeof(bool));

有两种方法可以解决这个问题:

1) 通过调用 ContentManager.Publish() 确保新创建的项目正在发布,因为 Orchard.Projections.Handlers.FieldIndexPartHandler 侦听发布事件以更新 FieldIndexPartRecord

2) 使用 IFieldIndexService 手动更新 FieldIndexPartRecord,请参阅 Orchard.Projections.Handlers.FieldIndexPartHandler 的实现以了解如何执行此操作

希望对您有所帮助。

:编辑

由于调用 Create(...Published)ContentManager.Published() 不会执行任何操作,因为该项目已被视为已发布。

您可以执行以下操作以强制发布逻辑 运行:

bool itemPublished = newItem.VersionRecord.Published;

// unpublish item first when it is already published as ContentManager.Publish() internally first checks for published flag and when set it aborts silently
//  -> this behaviour prevents calling publish listeners 
if (itemPublished)
  _contentManager.Unpublish(newItem);

// the following call will result in calls to IContentHandler.Publishing() / IContentHandler.Published()
_contentManager.Publish(newItem);

或者只是将项目创建为草稿,并在一切设置正确后发布它。

在某些情况下,简单的 contentManager.Publish() 是行不通的。 前段时间我遇到过类似的问题,实际上实现了一个简单的帮助服务来解决这个问题;这是摘录:

public T GetStringFieldValues<T>(ContentPart contentPart, string fieldName)
{
    var fieldIndexPart = contentPart.ContentItem.As<FieldIndexPart>();
    var partName = contentPart.PartDefinition.Name;

    return this.fieldIndexService.Get<T>(fieldIndexPart, partName, fieldName, string.Empty);
}

private void SetStringFieldValue(ContentPart contentPart, string fieldName, IEnumerable<int> ids)
{
    var fieldIndexPart = contentPart.ContentItem.As<FieldIndexPart>();
    var partName = contentPart.PartDefinition.Name;
    var encodedValues = "{" + string.Join("},{", ids) + "}";
    this.fieldIndexService.Set(fieldIndexPart, partName, fieldName, string.Empty, encodedValues, typeof(string));
}

我实际上已经构建了这个用于 MediaLibrary- 和 ContentPicker 字段(它们在内部将它们的值编码为字符串),因此它可能不适合您示例中的布尔字段。 但实现起来并不难,只需查看这些字段的现有驱动程序和处理程序即可。