I have a class that looks something like this:
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;
}
}
Hence, I can use the class like this:
MyClass a = "Hello!";
But in Raven DB it will just be stored like
"SomeProperty": {}
since it has no public properties. And it is quite useless.
To solve this I would make the _value private member a public property instead, like this:
public string Value { get; set; }
and Raven DB will store
"SomeProperty": { "Value": "Hello!" }
and it will be deserializable.
But I don't want this public property. Can I somehow make Raven DB serialize and deserialize the class as was it would a string? Like:
"SomeProperty": "Hello!"
Hi I know this is old but I thought I would add some additions to Ayendes' reply to help people who like me had the same issue and spent hours looking on forums for an answer (of which there were a few but none had any example that you could follow), it's not hard to figure this out but with an example I could have solved this in 10 minutes as opposed to spending a few hours.
My problems was that we have custom value type structs in our application the example I will use is EmailAddress. Unfortunately in Ravendb we could not run queries against these types without defining a custom serialiser.
Our Value Type looked Like this:
[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);
}
}
The type of document we wanted to save and query would look something like this
public class Customer
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public EmailAddress Email { get; set; }
}
The custom serialiser to store our email as a raw string and then convert it back to its value type on retrieval looked like this:
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);
}
}
Finally I wired it up and was able to query everything as follows:
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
}
}
}
You can write a JsonConverter and teach RavenDB how you want to store the data. After you write the converter, register it in the store.Conventions.CustomizeSerializer event.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With