6 votes

Puis-je faire en sorte que Raven DB sérialise un objet comme une chaîne de caractères, si j'ai créé un opérateur de conversion de type implicite ?

J'ai une classe qui ressemble à ceci :

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

Je peux donc utiliser la classe comme suit :

MyClass a = "Hello!";

Mais dans la base de données Raven, il sera simplement stocké comme suit

"SomeProperty": {}

puisqu'il n'a pas de propriétés publiques. Et il est tout à fait inutile.

Pour résoudre ce problème, je ferais en sorte que le membre privé _value devienne une propriété publique, comme ceci :

public string Value { get; set; }

et la base de données Raven stockera

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

et il sera désérialisable.

Mais je ne veux pas de cette propriété publique. Est-ce que je peux faire en sorte que Raven DB sérialise et désérialise la classe comme s'il s'agissait d'une chaîne de caractères ? Par exemple :

"SomeProperty": "Hello!"

12voto

Jesse Points 131

Bonjour, je sais que c'est vieux mais j'ai pensé ajouter quelques compléments à la réponse d'Ayendes pour aider les gens qui comme moi ont eu le même problème et ont passé des heures à chercher une réponse sur les forums (il y en avait quelques uns mais aucun n'avait d'exemple à suivre), ce n'est pas difficile à comprendre mais avec un exemple j'aurais pu le résoudre en 10 minutes au lieu de passer quelques heures.

Mon problème est que nous avons des structures de type valeur personnalisées dans notre application, l'exemple que j'utiliserai est EmailAddress. Malheureusement, dans Ravendb, nous ne pouvions pas exécuter de requêtes sur ces types sans définir un sérialisateur personnalisé.

Notre type de valeur se présente comme suit :

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

Le type de document que nous voulons sauvegarder et interroger ressemblerait à ceci

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

Le sérialiseur personnalisé pour stocker notre courriel en tant que chaîne brute et le reconvertir en son type de valeur lors de la récupération ressemblait à ceci :

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

Finalement, j'ai câblé le tout et j'ai pu interroger tout ce qui suit :

    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("testemail@gmail.com")
            };

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

6voto

frontsideair Points 221

Vous pouvez écrire un convertisseur Json et indiquer à RavenDB comment vous souhaitez stocker les données. Après avoir écrit le convertisseur, enregistrez-le dans l'événement store.Conventions.CustomizeSerializer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X