2012-05-17 5 views
6

Ho una classe che sembra qualcosa di simile:Posso rendere serializzato un oggetto Raven DB come se fosse una stringa, se ho creato un operatore di conversione di tipo implicito?

public class MyClass 
{ 
    string _value; 

    public static implicit operator MyClass (string value) 
    { 
     return new MyClass(value); 
    } 

    MyClass(string value) 
    { 
     // Do something... 
     _value = value; 
    } 

    public override string ToString() 
    { 
     // Do something... 
     return _value; 
    } 
} 

Quindi, posso utilizzare la classe in questo modo:

MyClass a = "Hello!"; 

Ma in Raven DB sarà solo essere conservato come

"SomeProperty": {} 

poiché non ha proprietà pubbliche. Ed è abbastanza inutile.

per risolvere questo vorrei fare il membro privato _value una proprietà pubblica, invece, in questo modo:

public string Value { get; set; } 

e Raven DB raccoglierò

"SomeProperty": { "Value": "Hello!" } 

e sarà deserializable.

Ma io non voglio questa proprietà pubblica. Posso in qualche modo rendere serializzato e deserializzare la classe Raven DB come se fosse una stringa? Come:

"SomeProperty": "Hello!" 

risposta

6

È possibile scrivere una JsonConverter e insegnare RavenDB come si desidera memorizzare i dati. Dopo aver scritto il convertitore, registrarlo nell'evento store.Conventions.CustomizeSerializer.

11

Ciao So che questo è vecchio ma ho pensato di aggiungere alcune aggiunte alla risposta di Ayendes per aiutare le persone che come me avevano lo stesso problema e passavano ore a cercare nei forum una risposta (di cui ce ne erano poche ma nessuna Ho avuto qualche esempio da seguire), non è difficile da capire, ma con un esempio avrei potuto risolverlo in 10 minuti anziché passare qualche ora.

I miei problemi consistevano nel disporre di strutture di tipo valore personalizzato nella nostra applicazione, l'esempio che utilizzerò è EmailAddress. Sfortunatamente in Ravendb non è stato possibile eseguire query su questi tipi senza definire un serializzatore personalizzato.

Il nostro tipo di valore si presentava così:

[DataContract(Namespace = DataContractNamespaces.ValueTypes)] 
public struct EmailAddress : IEquatable<EmailAddress> 
{ 
    private const char At = '@'; 

    public EmailAddress(string value) : this() 
    { 
     if (value == null) 
     { 
      throw new ArgumentNullException("value"); 
     } 

     this.Value = value; 
    } 

    public bool IsWellFormed 
    { 
     get 
     { 
      return Regex.IsMatch(this.Value, @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"); 
     } 
    } 

    public string Domain 
    { 
     get 
     { 
      return this.Value.Split(At)[1]; 
     } 
    } 

    [DataMember(Name = "Value")] 
    private string Value { get; set; } 

    public static bool operator ==(EmailAddress left, EmailAddress right) 
    { 
     return left.Equals(right); 
    } 

    public static bool operator !=(EmailAddress left, EmailAddress right) 
    { 
     return !left.Equals(right); 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
     { 
      return false; 
     } 

     return this.Equals(new EmailAddress(obj.ToString())); 
    } 

    public override int GetHashCode() 
    { 
     return this.Value.GetHashCode(); 
    } 

    public override string ToString() 
    { 
     return this.Value; 
    } 

    public bool Equals(EmailAddress other) 
    { 
     return other != null && this.Value.Equals(other.ToString(), StringComparison.OrdinalIgnoreCase); 
    } 
} 

Il tipo di documento abbiamo voluto salvare e di query sarebbe simile a questa

public class Customer 
{ 
    public Guid Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public EmailAddress Email { get; set; } 
} 

La serialiser personalizzato per conservare la nostra e-mail come grezzo stringa e quindi convertirlo di nuovo al suo tipo di valore sul recupero sembrava così:

public class EmailConverterTest : JsonConverter 
{ 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(EmailAddress); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     EmailAddress actualAddress = new EmailAddress(reader.Value.ToString()); 

     return actualAddress; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     EmailAddress actualAddress = (EmailAddress)value; 
     string stringEmail = actualAddress.ToString(); 
     writer.WriteValue(stringEmail); 
    } 
} 

Infine l'ho cablato e ho potuto interrogare tutto come segue:

public static void serializercustom(Newtonsoft.Json.JsonSerializer serialiser) 
    { 
     serialiser.Converters.Add(new EmailConverterTest()); 
    } 

    public static void TestCustomer() 
    { 
     using (var documentStore = new DefaultDocumentStore()) 
     { 
      documentStore.ConnectionStringName = Properties.Settings.Default.SandBoxConnection; 
      documentStore.Initialize(); 
      documentStore.Conventions.CustomizeJsonSerializer = new Action<Newtonsoft.Json.JsonSerializer>(serializercustom); 

      var customer = new Customer 
      { 
       Id = Guid.NewGuid(), 
       FirstName = "TestFirstName", 
       LastName = "TestLastName", 
       Email = new EmailAddress("[email protected]") 
      }; 

      // Save and retrieve the data 
      using (var session = documentStore.OpenSession()) 
      { 
       session.Store(customer); 
       session.SaveChanges(); 
      } 

      using (var session = documentStore.OpenSession()) 
      { 
       var addressToQuery = customer.Email; 
       var result = session.Query<Customer>(typeof(CustomerEmailIndex).Name).Customize(p => p.WaitForNonStaleResults()).Where(p => p.Email == addressToQuery); 

       Console.WriteLine("Number of Results {0}", result.Count()); // This always seems to return the matching document 
      } 
     } 
    } 
Problemi correlati