2011-07-30 11 views
10

Ho visto alcune idee su questo come invece di creare, aggiornare, inserire, eliminare (CRUD) utilizzare Get and Put. Quello è buono. Tuttavia, non ho ancora visto molto su come affrontare la complessità. Mi è stato detto, "basta scrivere un metodo per ogni tipo di query di cui hai bisogno".Esistono modelli di progettazione del livello dati NOSQL?

La maggior parte di NOSQL mi sembra a posto finchè non comincio a pensare ai qualificatori (una clausola where) - potrebbero esserci così tante varianti. Esiste già un buon schema per implementare i qualificatori in modo ragionevole, usando solo i nomi dei metodi & argomenti convenzionali? Forse c'è un qualche tipo di schema verbale/sostantivo che funziona bene, ma che non è un linguaggio a sé stante.

Non rispondo alla risposta "giusta" ... spero che ci siano alcune scuole di pensiero da cui ho potuto imparare.

trovato questo post del blog dal creatore di RavenDB: http://ayende.com/blog/4562/ravendb-index-management

Possiamo implementare più di un indice su una classe?

Ho anche scoperto che potrebbe essere possibile serializzare i delegati anonimi http://blogs.microsoft.co.il/blogs/aviwortzel/archive/2008/06/20/how-to-serialize-anonymous-delegates.aspx Suppongo che se è possibile, che potrebbero usare qualcosa di simile.

Ma cosa succede se non abbiamo accesso allo stesso assembly (ad esempio Silverlight). Trovato questo post qui: http://ayende.com/blog/4766/accessing-ravendb-from-silverlight

L'oggetto IEnumerable<T> è ricercato sul lato client o sul lato server? Quanto è specifico ottenere il lato server in NOSQL nel restringere il set di risultati prima di inviarlo via cavo, senza bloccarlo a un unico ID?

AGGIORNAMENTO: Ho finito con l'invio di email a Ayende da RavenDB. Ha risposto gentilmente alle domande che ho avuto (in basso):

Che cosa si può fare è scrivere:

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

Questo utilizza LINQ per capire il vostro intento, e poi invia la query al server usando la sintassi di RavenDB. Sul server, analizziamo la tua query, e Query Optimizer controlla se esiste un indice esistente in grado di rispondere a questa query e, in caso contrario, creerà per te un indice temporaneo.

Se si esegue una query sufficiente dell'indice temporaneo, RavenDB lo renderà permanente. Così, auto-ottimizzando le proprie operazioni.

Sei arrivato molto lontano con il caso d'uso "da Silverlight"?

Supportiamo pienamente Silverlight.

RavenDB può gestire più di un server di indicizzazione?

Sì. In effetti, abbiamo alcuni clienti che hanno> 500 indici in esecuzione senza problemi.

FINE DI INFORMAZIONI DA Ayende a RavenDB

sulla progettazione di un linguaggio di interrogazione (cioè FindAll/dove/delegato), Mongo sembrano ottenere un po 'di questa via JSON ... http://www.mongodb.org/display/DOCS/Indexes Vorrei sapere di più a proposito.

Questo sembra più vicino: http://www.mongodb.org/display/DOCS/MapReduce

Un filo interessante sulla serializzazione Serializing anonymous delegates in C#. Non è direttamente rilevante ... ma sto solo cercando di guardare sotto il cofano un po 'così so di più sui potenziali.

+0

Domanda pertinente [Architetture di accesso ai dati con DB Raven] (http://stackoverflow.com/questions/5909400/data-access-architectures-with-raven-db) – oleksii

+0

@olesii. Grazie. Ho dato un'occhiata. Sembra che abbiano riscontrato problemi simili. FindAll cosa? Come puoi implorare qualificatori? Posso vedere come il caching o gli scenari basati sull'iscrizione funzionerebbero bene, ma non tutto ciò che è più complicato di così. Sono curioso. – sgtz

+0

Ho postato una risposta. Con il repository corrente sono in grado di fare 'Find', che può restituire tutti i record se necessario. Ma ... non sono sicuro che questo sia il modo corretto. Le persone hanno il diritto di dire che ho assolutamente torto qui. Non sono riuscito a trovare una soluzione migliore però. – oleksii

risposta

4

Non sono sicuro che questo sia applicabile a NoSQL, ma ho implementato un modello Repository generico con Raven DB e qui c'è uno snippet.

In primo luogo, ho definito un paio di interfacce

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

e questa è un'implementazione accorciare

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

campione Uso di prova del campione

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

per creare, che utilizzano Trova (FirstOrDefault) metodo per asserire

[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 grazie. Non male. Immagino tu possa usare metodi anonimi per ripulirlo ancora. Il tuo Trova (Func exp) viene eseguito lato client o lato server? – sgtz

+0

@sgtz sentiti libero di modificare la risposta per migliorare la qualità (aggiungi metodi anonimi). Vedi, penso che quell'espressione sia esecuita sul server. Viene solo analizzato sul client, Raven DB quindi chiama semplicemente 'session.Query () ...'. Sono sicuro al 99% che Raven DB non costringa il client a caricare tutte le entità sul client e a filtrarle lì - no, invece accetta IQuariable e lo esegue sul lato server. Quindi solo il risultato filtrato necessario riaccordato. – oleksii

Problemi correlati