Пустое поле 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
Некоторые обходные пути:
- Используйте нетипизированную версию
Index
вместо этого для сценариев слияния. - использование
Upload
вместоMerge
, - Положил
[JsonProperty(NullValueHandling = NullValueHandling.Include)]
на свойствах вашего модельного класса, которые вам нужно явно установить в null в операции слияния (не рекомендуется, если в вашем индексе много полей). - Реализуйте пользовательский конвертер.
Я нашел виновника в источнике 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);