2011-10-13 3 views
3

J'ai commencé à apprendre NoSQL sur un exemple de RavenDB. Je l'ai commencé avec un modèle le plus simple, disons que nous avons des sujets qui ont été créés par les utilisateurs:Comment synchroniser les changements dans nosql db (ravendb)

public class Topic 
{ 
    public string Id { get; protected set; } 
    public string Title { get; set; } 
    public string Text { get; set; } 

    public DenormalizedUser User { get; set; } 
} 

public class DenormalizedUser 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 

public class User 
{ 
    public string Id { get; protected set; } 
    public string Name { get; set; } 
    public DateTime Birthdate { get; set; } 

    //some other fields 
} 

On n'a pas besoin du tout User pour afficher une Topic, donc je l'ai denormalized à DenormalizedUser, contenant un Id et un Name.

Alors, voici les questions:

1) Cette approche est correcte pour NoSQL?

2) Comment gérer les cas lorsque User change le Name? Dois-je mettre à jour manuellement tous les champs Name dans les classes dénormalisées?

+0

Je ne sais pas pour la question 1. En ce qui concerne 2, oui vous devez mettre à jour le champ pour « Nom » dans « DenormalizedUser » aussi parce que les chaînes, pour toutes fins utiles, sont gérées par valeur, et non référence. Je ne vois pas seulement pourquoi vous ne pouvez pas utiliser seulement 'User' - 'DenormalizedUser' des données inutiles et redondantes. _Edited (plusieurs fois) pour la clarté et la grammaire. J'ai besoin de plus de café. _ –

Répondre

3

Shaddix vous pouvez utiliser la fonction Raven DB Include pour charger l'utilisateur en utilisant le UserId de votre sujet.

var topic = _session.Load<Topic>(topicId) 
        .Customize(x => x.Include<Topic>(y => y.UserId)); 

var user = _session.Load<User>(topic.UserId); 

La charge pour sujet sera «pré-charge l'utilisateur et les charges ne se traduira par une requête GET. (Je ne pouvais pas répondre directement à votre réponse à Ayende en raison de ma réputation).

Vous utilisez également la fonction alternative (et probablement plus claire) .Include() sans Customize().

http://docs.ravendb.net/consumer/querying/handling-document-relationships.html

+0

Merci, c'est la voie à suivre, mais si je demande la liste des rubriques et que j'ai non seulement un 'User' comme référence dans' Topic', la syntaxe devient trop compliquée par rapport à NH (exemple sur le commentaire de dlang – Shaddix

+0

Il existe un exemple d'interrogation dans le lien des relations de document ci-dessus. 'sujets var = session.Query () .Customize (x => x.Include (t => t.UserId)) ToList();' Vous pouvez ensuite ajouter chacun à votre modèle de vue:. 'foreach (rubrique var dans les rubriques) { var user = session.Load (topic.UserId); // viewmodel list.Add (nouveau TopicViewModel {....}); Il n'est pas aussi propre que NH par exemple, mais je pense que le temps gagné et les maux de tête perdus en utilisant Raven l'emportent. Vous pouvez également l'intégrer dans une méthode d'extension pour nettoyer vos contrôleurs/services si nécessaire. – Matt

+0

c'est un bon point de penser à la méthode d'extension, oui. Merci pour le lien fourni, il décrit vraiment toutes les façons possibles ici. C'est dommage que tout le bon et "natif" C# api ne l'ait pas .. Je vais aller jeter un coup d'oeil au monde de MongoDB, mais je pense que leur API serait pire à d'autres points. – Shaddix

3

Shaddix, Vous n'avez pas besoin de dénormaliser, vous pouvez tenir une référence à l'identifiant, puis inclure que lorsque vous chargez du serveur

+0

Merci, Ayende, mais si je n'ai que UserId, comment pourrais-je accéder à 'topic.User.Name'? Bien sûr, je peux faire '_session.Query (). Où (x => x.Id == topic.UserId)', mais ce serait beaucoup moins pratique que dans le SGBDR avec NHibernate où je pourrais avoir une référence à la ' User' dans le 'Topic', ou existe-t-il d'autres moyens? – Shaddix

2

1) Oui, cette approche fonctionne très bien et le résultat est, que vous avez seulement besoin de charger le document-sujet lorsque vous voulez l'afficher avec le nom de son utilisateur. Cependant, comme le dit Ayende, la performance sera presque la même que si vous ne dénormalisiez pas l'utilisateur et que vous l'incluiez simplement en cas de besoin. Si vous ne vous inquiétez pas du déploiement de plusieurs serveurs, je recommande cette approche.

2) Si vous voulez vraiment dénormaliser l'utilisateur, vous pouvez mettre à jour toutes les rubriques faisant référence à cet utilisateur simplement avec une opération basée sur un ensemble. Regardez ceci: http://ravendb.net/faq/denormalized-updates

+0

Je suis d'accord pour faire '.Include', surtout parce que ce n'est encore qu'un seul DB-hit, je suis seulement inquiet de la facilité d'utilisation dans ce cas. Disons que j'aimerais obtenir un ViewModel avec une liste de sujets et leurs utilisateurs, comment est-ce que je ferais ça avec Include? '_session.Query () .Inclure (x => x.UserId) .Sélectionnez (topic => new {Sujet = topic, Utilisateur = _session.Query () .Where (u => u.Id == topic. UserId)}) '? Dans NHibernate ce serait seulement: '_session.Query () .Fetch (x => x.User)' avec référence à 'User' dans le' Topic', et il semble beaucoup plus propre, espérons trouver similaire avec nosql ... – Shaddix

+0

btw, merci pour le lien denormalized-updates, vraiment utile – Shaddix

+0

Votre exemple de code pour utiliser '.Include' est vraiment sympa et oui, ça fonctionne de cette façon. J'utilise NHibernate depuis de nombreuses années et je suis d'accord, utiliser '.Fetch' et référencer directement l'utilisateur est beaucoup plus propre. Si quelqu'un utilise RavenDB correctement, vous le verrez dans son modèle de données. –

Questions connexes