2011-07-30 9 views
10

He visto algunas ideas sobre esto, en lugar de utilizar Create, Update, Insert, Delete (CRUD) como Get and Put. Eso es bueno. Sin embargo, aún no he visto mucho sobre cómo lidiar con la complejidad. Me han dicho, "solo escribe un método para cada tipo de consulta que necesites".¿Hay patrones de diseño de capa de datos NOSQL?

La mayoría de NOSQL parece bien para mí hasta que comience a pensar en eliminatorias (una cláusula where) - no puede haber tantas variaciones. ¿Existe ya un buen esquema para implementar calificadores de una manera sensata, usando solo los nombres de métodos & convenciones de argumentos? Quizás haya algún tipo de esquema de verbo/sustantivo que funcione bien, pero que no sea un lenguaje en sí mismo.

no estoy después de la respuesta 'correcta' ... Estoy esperando que hay algunas escuelas de pensamiento que podía aprender.

Encontrado esta entrada del blog del fabricante de RavenDB: http://ayende.com/blog/4562/ravendb-index-management

¿Se puede aplicar más de un índice en una clase?

Incluso encontré que sería posible serializar delegados anónimos http://blogs.microsoft.co.il/blogs/aviwortzel/archive/2008/06/20/how-to-serialize-anonymous-delegates.aspx Supongo que si esto es posible, que podrían usar algo como esto.

Pero ¿y si no tenemos acceso al mismo conjunto (por ejemplo, Silverlight). He encontrado esta publicación aquí: http://ayende.com/blog/4766/accessing-ravendb-from-silverlight

¿Se ha buscado el objeto IEnumerable<T> del lado del cliente o del servidor? ¿Qué tan específico podemos llegar al lado del servidor en NOSQL al reducir el conjunto de resultados antes de enviarlo de regreso a través del cable, sin bloquearlo a un único ID?

ACTUALIZACIÓN: terminé enviando un correo electrónico a Ayende desde RavenDB. Él amablemente respondió a las preguntas que tenía (abajo):

Lo que puede hacer es escribir:

public IEnumerable<T> FindAll(Expression<Func<T,bool>> whereClause) 
    { 
     return session.Query<T>().Where(whereClause).ToList(); 
    } 

Esto utiliza LINQ a la figura de su intención, y luego envía la consulta al servidor usando la sintaxis de RavenDB. En el servidor, analizamos su consulta, y el optimizador de consultas comprueba si hay un índice existente que pueda responder a esta consulta, y si no existe, creará un índice temporal para usted.

Si consulta que suficiente índice temporal, RavenDB hará que sea permanente. Por lo tanto, auto optimizando sus propias operaciones.

¿Llegó muy lejos con el caso de uso "de Silverlight"?

Estamos apoyando plenamente Silverlight.

¿Puede RavenDB manejar más de un lado del servidor de índice?

Sí. De hecho, tenemos algunos clientes que tienen más de 500 índices funcionando sin problemas.

FIN DE INFORMACIÓN DE Ayende en RavenDB

En el diseño de un lenguaje de consulta (es decir FindAll/dónde/delegado), parece mongo para lograr un poco de esto a través de JSON ... http://www.mongodb.org/display/DOCS/Indexes Me gustaría saber más al respecto.

Esto suena más cerca: http://www.mongodb.org/display/DOCS/MapReduce

Un tema interesante de la serialización Serializing anonymous delegates in C#. No es directamente relevante ... pero solo intento mirar un poco por debajo del capó para saber más sobre los potenciales.

+0

Pregunta relevante [Arquitecturas de acceso a datos con Raven DB] (http://stackoverflow.com/questions/5909400/data-access-architectures-with-raven-db) – oleksii

+0

@olesii. Gracias. Eché un vistazo. Parecen haber golpeado problemas similares. Encontrar todo ¿Qué? ¿Cómo puedes implicar a los calificadores? Puedo ver cómo el almacenamiento en caché o los escenarios basados ​​en la membresía funcionarían bien, pero no en algo que sea más complicado que eso. Soy curioso. – sgtz

+0

He publicado una respuesta. Con el repositorio actual, puedo hacer 'Buscar', que puede devolver todos los registros si es necesario. Pero ... No estoy seguro de que este sea el camino correcto. La gente tiene derecho a decir que estoy absolutamente equivocado aquí. Sin embargo, no pude encontrar una mejor solución. – oleksii

Respuesta

4

No estoy seguro de que esto sea aplicable a NoSQL, pero implementé un patrón de Repositorio genérico con Raven DB y aquí hay un fragmento.

En primer lugar, he definido un par de interfaces de

internal interface ISessionProvider : IDisposable 
{ 
    IDocumentSession OpenSession(); 
    void CloseSession(); 
} 

public interface IDataAccessManager : IDisposable 
{ 
    void Initialize(); 
    void OpenSession(); 
    void CloseSession(); 
} 

public interface IRepository<T> where T : Entity 
{ 
    IQueryable<T> Query(); 
    IEnumerable<T> Find(Func<T, bool> exp); 
    T FirstOrDefault(Func<T, bool> exp); 

    void Delete(T entity); 
    void Add(T entity); 
    void Save(); 

    string PutAttachment(string key, byte[] data); 
    Attachment GetAttachment(string key); 
    void DeleteAttachment(string key); 
} 

y esta es una aplicación acortar

internal class SessionProvider : ISessionProvider 
{ 
    ... 

    public IDocumentSession OpenSession() 
    { 
     session = store.OpenSession(); 
     return session; 
    } 

    public void CloseSession() 
    { 
     if (session != null) 
     { 
      session.Dispose(); 
     } 
    } 
} 

public class DataAccessManager : IDataAccessManager 
{ 
    ... 

    public void Initialize() 
    {  
     store = new DocumentStore 
     { 
      ConnectionStringName = ConnectionString 
     }; 
     store.Initialize(); 
     store.DatabaseCommands.EnsureDatabaseExists(dbName); 

     provider = new SessionProvider(store); 
    } 

    public void OpenSession() 
    { 
     session = provider.OpenSession(); 
    } 

    public void CloseSession() 
    { 
     provider.CloseSession(); 
    } 
} 


public class Repository<T> : IRepository<T> where T : Entity 
{ 
    ... 

    public IEnumerable<T> Find(Func<T, bool> exp) 
    { 
     return AsQuaribale().Where(exp); 
    } 

    public void Add(T entity) 
    { 
     session.Store(entity); 
    } 

    public void Save() 
    { 
     session.SaveChanges(); 
    } 

    public string PutAttachment(string key, byte[] data) 
    { 
     Guid? etag = null; 
     var metadata = new RavenJObject 
     { 
      {"owner", Thread.CurrentPrincipal.Identity.Name}, 
      {"filename", key} 
     }; 
     session.Advanced.DatabaseCommands.PutAttachment(key, etag, data, metadata); 

     return key; 
    } 

    public Attachment GetAttachment(string key) 
    { 
     return session.Advanced.DatabaseCommands.GetAttachment(key); 
    } 

    private IQueryable<T> AsQuaribale() 
    { 
     return session.Query<T>().Customize(x => x.WaitForNonStaleResultsAsOfNow(Timeout)); 
    } 
} 

Ejemplo de uso

private void SendData() 
{ 
    try 
    { 
     dataManager.OpenSession(); 
     repository = new Repository<MyDomainType>(); 

     ... 

     foreach (string path in paths) 
     {   
      //read file to memory 
      byte[] data = File.ReadAllBytes(path); 
      string fName = Path.GetFileName(path); 
      myDomainType.Name = fName; 

      //save data in memory and metadata to the database 
      string key = repository.PutAttachment(
       myDomainType.Id.ToString(), data); 

      repository.Add(myDomainType); 
     } 

     repository.Save(); 
    } 
    catch (Exception ex) 
    { 
     AppManager.LogException(ex); 
    } 
    finally 
    { 
     dataManager.CloseSession(); 
     dataManager.Dispose();  
    } 
} 

prueba de la muestra para crear, que utilizan Find (FirstOrDefault) método para la afirmación

[Test] 
public void CreateValueTest() 
{ 
    var repository = ContainerService.Instance.Resolve<IRepository<DummyType>>(); 
    var expected = new DummyType(); 
    repository.Add(expected); 
    repository.Save(); 
    DummyType actual = repository.FirstOrDefault(item => item.Id == expected.Id); 

    Assert.IsTrue(expected == actual); 
} 
+0

@olesii +1 gracias. No está mal. Supongo que puedes usar métodos anónimos para limpiarlo un poco más. ¿Su Find (Func exp) se ejecuta en el lado del cliente o en el servidor? – sgtz

+0

@sgtz no dude en editar la respuesta para mejorar la calidad (agregue métodos anónimos). Mira, creo que esa expresión está exequida en el servidor. Se acaba de analizar en el cliente, Raven DB luego simplemente llame a 'session.Query () ...'. Estoy 99% seguro de que Raven DB no obliga al cliente a cargar todas las entidades al cliente y filtrarlas allí; no, en cambio, lleva a IQuariable y lo ejecuta en su servidor. Por lo tanto, solo se recupera el resultado filtrado necesario. – oleksii