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.
Este blogpost puede ayudarle a decidir: http://daniellang.net/how-to-handle-relations-in-ravendb/ – dasheddot
Gracias dasheddot, eso es realmente útil, gracias. –
Esto parece interesante. Mapas múltiples/índices de reducción [aquí] (http: // ayende.com/blog/89089/ravendb-multi-maps-reduce-indexes) – biofractal