2016-12-13 8 views
2

Я использую Microsoft.Azure.Search версии 3.0.1,Azure SDK Поиск нулевой поле не установлен на Merge действия

Я пытаюсь следующее:

// 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 операция слияния обновляет поле, равное нулю. И на самом деле, если я сделаю этот запрос Http вручную с помощью JSON, это правда. Но SDK не обновляет поле (ы) до нуля. Что мне не хватает?

ответ

1

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

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

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

Thank you Bruce! Я не знал о нетипизированной версии (используя документ). Я буду использовать это вместо пользовательских преобразователей. Я также забыл о JsonPropertyAttribute. Можете ли вы сказать, почему не рекомендуется использовать JsonProperty в каждом поле? –

+0

Производительность в основном. Если у вас очень широкая схема (думаю, 100 полей), отправка 100 единиц нулей для каждого документа в пакетном запросе индекса очень расточительна по пропускной способности сети. –

1

Я нашел the culprit in the Azure Search SDK source.

Строка 51, settings.NullValueHandling = NullValueHandling.Ignore; переопределяет настройку, которую я пытался установить. Вероятно, я расскажу об этом в Гитубе.

В настоящее время я использую пользовательский конвертер в качестве обходного пути.

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()); 

// ... 

Edit:

Две другие улучшенные варианты, перечисленные Брюс: с помощью документа, который нетипизированным, и используя JsonPropertyAttribute на поле, чтобы получить правильную сериализации , Использование документа идеально подходит для моего случая использования, не проблема сериализации или пользовательскими преобразователей:

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);