2012-05-17 6 views
6

tengo una clase que se ve algo como esto:¿Puedo hacer que Raven DB serialice un objeto como lo haría con una cadena, si he creado un operador de conversión de tipo implícito?

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

Por lo tanto, puedo utilizar la clase como esta:

MyClass a = "Hello!"; 

Pero en Cuervo DB sólo se almacenará como

"SomeProperty": {} 

ya que no tiene propiedades públicas. Y es bastante inútil.

Para resolver esto haría que el miembro privado _value una propiedad pública en su lugar, como este:

public string Value { get; set; } 

y Raven DB almacenaré

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

y será deserializable.

Pero no quiero esta propiedad pública. ¿De alguna manera puedo hacer que Raven DB serialice y deserialice la clase como lo haría con una cadena? Me gusta:

"SomeProperty": "Hello!" 

Respuesta

6

Puede escribir un JsonConverter y enseñarle a RavenDB cómo desea almacenar los datos. Después de escribir el convertidor, insértelo en el evento store.Conventions.CustomizeSerializer.

11

Hola, sé que esto es antiguo, pero pensé que agregaría algunas adiciones a la respuesta de Ayendes para ayudar a las personas que me gustaban a tener el mismo problema y pasé horas buscando respuestas en los foros (de los cuales había algunos pero ninguno tenía algún ejemplo que pudieras seguir), no es difícil resolver esto, pero con un ejemplo podría haberlo resuelto en 10 minutos en lugar de pasar unas horas.

Mi problema es que tenemos estructuras de tipo de valor personalizado en nuestra aplicación, el ejemplo que voy a utilizar es EmailAddress. Desafortunadamente en Ravendb no pudimos ejecutar consultas contra estos tipos sin definir un serializador personalizado.

Nuestro Valor Tipo veía así:

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

El tipo de documento que queríamos guardar y consulta sería algo como esto

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

El serializador personalizado para guardar nuestro correo electrónico como una prima cadena y luego convertirlo a su tipo de valor en la recuperación se veía así:

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

Finalmente lo conecté y pude consultar todo de la siguiente manera:

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 
      } 
     } 
    } 
Cuestiones relacionadas