Пустое поле Azure Search SDK не задано при действии слияния

Я использую 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 к нулю. Это игнорирует это. Если я устанавливаю ненулевое значение, оно устанавливает его.

Согласно документации здесь операция слияния обновляет поле до нуля. И на самом деле, если я сделаю этот Http-запрос вручную с помощью JSON, это правда. Но SDK не обновляет поле (я) до нуля. Что мне не хватает?

2 ответа

Решение

Это известное ограничение типичных перегрузок Index семейство методов. Проблема подробно описана здесь: https://github.com/Azure/azure-sdk-for-net/issues/1804

Некоторые обходные пути:

  1. Используйте нетипизированную версию Index вместо этого для сценариев слияния.
  2. использование Upload вместо Merge,
  3. Положил [JsonProperty(NullValueHandling = NullValueHandling.Include)] на свойствах вашего модельного класса, которые вам нужно явно установить в null в операции слияния (не рекомендуется, если в вашем индексе много полей).
  4. Реализуйте пользовательский конвертер.

Я нашел виновника в источнике Azure Search SDK.

Строка 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());

// ...

Редактировать:

Брюс указал два других превосходных варианта: использование нетипизированного 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);
Другие вопросы по тегам