2012-05-08 4 views
8

Je voudrais avoir une référence entre deux entités stockées dans la base de données de documents RavenDB. Comme ce n'est pas un db relationnel, je sais que je suis supposé utiliser la technique de référence dénormalisée décrite dans la documentation de RavenDBs. Alors qu'au début, cela semble bien, une fois que je commence à créer une «hiérarchie» de domaine du monde réel, y compris des références bidirectionnelles, l'effort de maintenir toutes ces références à jour semble disproportionné. Je sens que je vais peut-être aller mal quelque part. Pouvez-vous expliquer la façon la plus simple et la plus simple de modéliser une hiérarchie de domaine raisonnablement complexe en utilisant RavenDB?Comment implémenter des références dénormalisées dans RavenDB

Merci

+0

Ce blog peut vous aider à décider: http://daniellang.net/how-to-handle-relations-in-ravendb/ – dasheddot

+0

Merci dasheddot, c'est vraiment utile, merci. –

+0

Cela semble intéressant. Cartes multiples/Réduire les index [ici] (http: // ayende.com/blog/89089/ravendb-multi-cartes-réduisent-index) – biofractal

Répondre

6

Je ne suis pas sûr que cela va assez aller loin pour répondre à votre question, mais voici comment je vais sur la création d'un dénormalisées de référence dans RavenDB (cela est pris à partir du code réel non essentiels supprimés pour plus de clarté)

domaine

public class User : IUserIdentity 
{ 
    public string UserName { get; set; } 
    public IEnumerable<string> Claims { get; set; } 
    public string Id { get; set; } 
    public Guid FormsAuthenticationGuid { get; set; } 
} 

public class Assessment 
{ 
    public string Id { get; set; } 
    public UserReference User { get; set; } 
    public AssessmentState State { get; set; } 
} 

Vous pouvez voir que j'ai une classe Assessment qui fait référence à un User. Cette référence utilisateur est gérée à l'aide de la classe UserReference ci-dessous.

dénormalisées Référence

public class UserReference 
{ 
    public string Id { get; set; } 
    public string UserName { get; set; } 

    public static implicit operator UserReference(User user) 
    { 
     return new UserReference 
       { 
         Id = user.Id, 
         UserName = user.UserName 
       }; 
    } 
} 

Notez comment la classe de référence porte également le UserName. Cette valeur ne changera pas très souvent mais elle peut changer, nous avons donc besoin d'un moyen de mettre à jour la propriété UserName dans la propriété UserReference de la classe Assessment. Pour faire la modification, nous devons d'abord trouver les bonnes instances de RavenDB et pour cela nous avons besoin d'un index.

Raven Index

public class Assessment_ByUserId : AbstractIndexCreationTask<Assessment> 
{ 
    public Assessment_ByUserId() 
    { 
     Map = assessments => from assessment in assessments 
           select new 
            { 
              User_Id = assessment.User.Id 
            }; 
    } 
} 

Cet indice doit être invoqué chaque fois qu'une valeur de UserNameUser est mis à jour. J'ai une classe UserService qui m'aide à coordonner toutes mes fonctions liées à l'utilisateur, donc c'est là que j'ai mis ce code.

Je réutilise ce code pour d'autres références afin qu'il ait été extrait un peu. Cela peut vous aider à créer les hiérarchies les plus complexes (ou peut-être que le «graphique de domaine» est une meilleure description) que vous voulez.

UserService

public static void SetUserName(IDocumentSession db, string userId, string userName) 
{ 
    var user = db.Load<User>(userId); 
    user.UserName = userName; 
    db.Save(user); 
    UpdateDenormalizedReferences(db, user, userName); 
} 

private static void UpdateDenormalizedReferences(IDocumentSession db, User user, string userName) 
{ 
    db.Advanced.DatabaseCommands.UpdateByIndex(
      RavenIndexes.IndexAssessmentByUserId, 
      GetQuery(user.Id), 
      GetUserNamePatch(userName), 
      allowStale: true); 

} 

private static IndexQuery GetQuery(string propertyValue, string propertyName = "User_Id") 
{ 
    return new IndexQuery {Query = string.Format("{0}:{1}", propertyName, propertyValue)}; 
} 

private static PatchRequest[] GetUserNamePatch(string referenceValue, string referenceName = "User") 
{ 
    return new[] 
      { 
        new PatchRequest 
        { 
          Type = PatchCommandType.Modify, 
          Name = referenceName, 
          Nested = new[] 
            { 
              new PatchRequest 
              { 
                Type = PatchCommandType.Set, 
                Name = "UserName", 
                Value = referenceValue 
              } 
            } 
        } 
      }; 
} 

Ce qu'il est. Et vous savez, maintenant que je dépose tout cela, je peux voir ce que vous voulez dire. Il est beaucoup de travail juste pour mettre à jour une référence. Peut-être que le code de service peut être rendu plus SEC et réutilisé pour différents types de relations, mais je ne vois pas comment éviter d'écrire beaucoup d'index, un par type référencé.

+0

Grand, merci biofractal, j'essayais un itinéraire beaucoup plus complexe, cela semble idéal. –

Questions connexes