practices framework data best .net design-patterns nosql data-access-layer

.net - data - entity framework mongodb



¿Hay patrones de diseño de capa de datos NOSQL? (1)

He visto algunas ideas al respecto, en lugar de usar Create, Update, Insert, Delete (CRUD) como Get y 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".

La mayor parte de NOSQL me parece bien hasta que empiezo a pensar en calificadores (una cláusula where) - podría haber tantas variaciones. ¿Existe ya un buen esquema para implementar calificadores de una manera sensata, usando solo nombres de métodos y convenciones argumentales? 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 buscando la respuesta "correcta" ... Espero que haya algunas escuelas de pensamiento de las que pueda aprender.

Encontré esta publicación del blog del fabricante de RavenDB: http://ayende.com/blog/4562/ravendb-index-management

¿Podemos implementar 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, ¿qué ocurre si no tenemos acceso al mismo conjunto (por ejemplo, Silverlight)? Encontré este post aquí: http://ayende.com/blog/4766/accessing-ravendb-from-silverlight

¿ IEnumerable<T> busca 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 de RavenDB. Él amablemente respondió las preguntas que tenía (a continuación):

Lo que puedes hacer es escribir:

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

Esto usa linq para descubrir 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 consultas ese índice temporal lo suficiente, RavenDB lo hará permanente. Por lo tanto, auto optimizando sus propias operaciones.

¿Llegaste muy lejos con el caso de uso "de Silverlight"?

Estamos totalmente a favor de 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

Al diseñar un lenguaje de consulta (es decir, FindAll / where / delegate), mongo parece lograr un poco de esto a través de JSON ... http://www.mongodb.org/display/DOCS/Indexes Desearía saber más sobre él.

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

Un hilo interesante sobre la serialización de la serialización de delegados anónimos en C # . No es directamente relevante ... pero solo intento mirar un poco por debajo del capó para saber más sobre los potenciales.


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.

Primero, definí algunas interfaces

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 esto es una implementación abreviada

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

Muestra 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 muestra para create, que utiliza el método Find (FirstOrDefault) para assert

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