2016-12-13 1 views
2

Ich verwende Microsoft.Azure.Search Version 3.0.1Azure Search SDK null Feld nicht auf Merge Aktion gesetzt

Ich versuche folgendes:

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

Dies ist keine Einstellungen ApprovedOn auf null. Es ignoriert es. Wenn ich einen Wert ungleich Null einstelle, wird dieser Wert gesetzt.

Gemäß der Dokumentation here aktualisiert die Zusammenführungsoperation das Feld auf Null. Und in der Tat, wenn ich diese HTTP-Post-Anfrage manuell mit JSON mache, ist dies wahr. Das SDK aktualisiert das Feld (die Felder) jedoch nicht auf null. Was vermisse ich?

Antwort

1

Dies ist eine bekannte Einschränkung der typisierten Überlastungen der Index Familie von Methoden. Das Problem wird hier im Detail beschrieben: https://github.com/Azure/azure-sdk-for-net/issues/1804

Einige Lösungen:

  1. Verwenden Sie die nicht typisierte Version von Index statt für Merge-Szenarien.
  2. Verwenden Sie Upload anstelle von Merge.
  3. Setzen Sie [JsonProperty(NullValueHandling = NullValueHandling.Include)] auf die Eigenschaften Ihrer Modellklasse, die Sie in einer Zusammenführungsoperation explizit auf Null setzen müssen (nicht empfohlen, wenn Sie viele Felder in Ihrem Index haben).
  4. Implementieren Sie einen benutzerdefinierten Konverter.
+0

Danke Bruce! Ich war mir der untypisierten Version (mit dem Dokument) nicht bewusst. Ich werde das anstelle von benutzerdefinierten Konvertern verwenden. Ich hatte auch das JsonPropertyAttribute vergessen. Können Sie sagen, warum es nicht empfehlenswert ist, die JsonProperty in jedem Feld zu haben? –

+0

Leistung hauptsächlich. Wenn Sie ein sehr weites Schema haben (denken Sie an 100 Felder), ist das Verschicken von 100 Nullen für jedes Dokument in einer Index-Stapelanforderung sehr verschwenderisch für die Netzwerkbandbreite. –

1

Ich fand the culprit in the Azure Search SDK source.

Zeile 51, settings.NullValueHandling = NullValueHandling.Ignore; überschreibt die Einstellung, die ich versucht habe zu setzen. Ich werde wahrscheinlich in Github darüber sprechen.

Momentan verwende ich einen benutzerdefinierten Konverter als Workaround.

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

Wie in

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

// ... 

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

// ... 

Edit:

Zwei weitere überlegen aufgeführten Optionen von Bruce: Dokument verwendet, die nicht typisiert ist, und mit Hilfe der JsonPropertyAttribute auf dem Feld die richtige Serialisierung zu erhalten . Dokument zu verwenden ist ideal für meinen Anwendungsfall, keine Serialisierung Problem oder benutzerdefinierter Konverter:

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