2012-05-08 13 views
8

Me gustaría tener una referencia entre dos entidades almacenadas en la base de datos de documentos de RavenDB. Como esto no es un DB relacional, sé que se supone que debo usar la técnica de Referencia Desormalizada que se describe en la documentación de RavenDBs. Aunque al principio esto parece estar bien, una vez que empiezo a crear una 'jerarquía' de dominio del mundo real que incluye referencias bidireccionales, el esfuerzo de mantener todas esas referencias actualizadas parece desproporcionado. Siento que puedo estar equivocado en alguna parte.¿Cómo implemento las referencias desnormalizadas en RavenDB?

¿Puede explicar la mejor y más sencilla forma de modelar una jerarquía de dominios razonablemente compleja utilizando RavenDB?

Gracias

+0

Este blogpost puede ayudarle a decidir: http://daniellang.net/how-to-handle-relations-in-ravendb/ – dasheddot

+0

Gracias dasheddot, eso es realmente útil, gracias. –

+0

Esto parece interesante. Mapas múltiples/índices de reducción [aquí] (http: // ayende.com/blog/89089/ravendb-multi-maps-reduce-indexes) – biofractal

Respuesta

6

No estoy seguro de si esto va lo suficientemente lejos para responder a su pregunta, pero aquí es cómo hago para la creación de una referencia sin normalizar en RavenDB (esto es tomado de código real con lo no esencial retiradas para mayor claridad)

dominio

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

Se puede ver que tengo una clase Assessment que hace referencia a un User. Esta referencia de usuario se administra utilizando la clase UserReference a continuación.

desnormalizado Referencia

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

Nota cómo la clase de referencia también lleva el UserName. Este valor no cambiará muy a menudo, pero puede cambiar, por lo que necesitamos una forma de actualizar la propiedad UserName en la propiedad UserReference que se encuentra en la clase Assessment. Para realizar el cambio primero debemos encontrar las instancias Assessment correctas de RavenDB y para eso necesitamos un índice.

Índice Cuervo

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

Este índice debe ser invocado cada vez que se actualiza un User 's UserName valor. Tengo una clase UserService que me ayuda a coordinar todas mis funciones relacionadas con el usuario, así que ahí es donde pongo este código.

Reutilizo este código para otras referencias, por lo que ha sido abstraído un poco. Esto puede ayudarlo a crear jerarquías más complejas (o quizás 'gráfico de dominio' es una mejor descripción) que desea.

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

Eso es todo. Y sabes, ahora que lo arreglo todo, puedo ver a qué te refieres. Es es un montón de trabajo solo para actualizar una referencia. Tal vez el código de servicio se puede hacer más DRY y reutilizar para diferentes tipos de relaciones, pero no veo cómo evitar escribir muchos índices, uno por tipo de referencia.

+0

Genial, gracias biofractal, estaba intentando una ruta mucho más compleja, esto parece ideal. –

Cuestiones relacionadas