未在合并操作中设置 Azure 搜索 SDK 空字段

Azure Search SDK null field not set on Merge action

我正在使用 Microsoft.Azure.Search 版本 3.0.1,

我正在尝试以下操作:

// subset of my index's fields
private class SyncFields
{   
    public string Id { get; set; }
    public DateTimeOffset? ApprovedOn { get; set; }
    public DateTimeOffset? IgnoredOn { get; set; }
}

public void Sync()
{
    var sync = new SyncFields
    {
        Id = "94303",
        ApprovedOn = null,
        IgnoredOn = DateTime.UtcNow
    };

    var searchClient = new SearchServiceClient("xxxx",
        new SearchCredentials("xxxx"));
    searchClient.SerializationSettings.NullValueHandling = NullValueHandling.Include;

    using (var client = searchClient.Indexes.GetClient("xxxx"))
    {
        client.SerializationSettings.NullValueHandling = NullValueHandling.Include;
        var batch = IndexBatch.Merge<SyncFields>(new[] { sync });
        client.Documents.Index<SyncFields>(batch);
    }
}

这不是设置 ApprovedOn 为 null。它忽略了它。如果我设置一个非空值,它会设置它。

根据文档 here,合并操作会将字段更新为空。事实上,如果我用 JSON 手动发出这个 Http post 请求,这是真的。但 SDK 并未将字段更新为空。我错过了什么?

我找到了 the culprit in the Azure Search SDK source

第 51 行,settings.NullValueHandling = NullValueHandling.Ignore; 覆盖了我尝试设置的设置。我可能会在 Github.

中对此提出一个问题

目前,我使用自定义转换器作为解决方法。

public class DefaultDateTimeOffsetIsNullConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(DateTimeOffset?));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var date = (DateTimeOffset?)value;
        if (date == default(DateTimeOffset))
        {
            writer.WriteNull();
        }
        else
        {
            writer.WriteValue(date);
        }
    }

    public override bool CanRead => false;

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

var sync = new SyncFields
{
    Id = "94303",
    ApprovedOn = default(DateTimeOffset), // set to null
    IgnoredOn = DateTime.UtcNow
};

// ...

client.SerializationSettings.Converters.Add(new DefaultDateTimeOffsetIsNullConverter());

// ...

编辑:

Bruce 列出的其他两个高级选项:使用未类型化的 Document,并在字段上使用 JsonPropertyAttribute 以获得正确的序列化。使用 Document 非常适合我的用例,没有序列化问题或自定义转换器:

var sync = new Document
{
    ["Id"] = "94303",
    ["ApprovedOn"] = null,
    ["IgnoredOn"] = null
};

// ... the same as before:
var batch = IndexBatch.Merge(new[] { sync });
await client.Documents.IndexAsync(batch);

这是 Index 系列方法的类型化重载的已知限制。此处详细描述了该问题:https://github.com/Azure/azure-sdk-for-net/issues/1804

一些解决方法:

  1. 使用 Index 的无类型版本代替合并方案。
  2. 使用 Upload 而不是 Merge
  3. [JsonProperty(NullValueHandling = NullValueHandling.Include)] 放在您需要在合并操作中显式设置为 null 的模型 class 的属性上(不推荐 如果您有索引中有很多字段)。
  4. 实现自定义转换器。