Существуют ли шаблоны проектирования слоев NOSQL?

Я видел несколько идей по этому поводу, а не как Create, Update, Insert, Delete (CRUD), используя Get и Put. Это хорошо. Тем не менее, я еще не видел много способов справиться со сложностью. Мне сказали: "Просто напишите метод для каждого типа запроса, который вам нужен".

Большинство NOSQL кажется мне в порядке, пока я не начну думать о квалификаторах (предложение where) - может быть так много вариантов. Есть ли уже хорошая схема для реализации квалификаторов разумным способом, используя только имена методов и условные условные обозначения? Возможно, существует какая-то схема глагола/существительного, которая работает хорошо, но которая не является самостоятельным языком.

Я не после "правильного" ответа... Я надеюсь, что есть несколько школ мысли, из которых я мог бы научиться.

Нашел это сообщение в блоге от создателя RavenDB: http://ayende.com/blog/4562/ravendb-index-management

Можем ли мы реализовать более одного индекса для класса?

Я даже обнаружил, что возможно сериализовать анонимных делегатов http://blogs.microsoft.co.il/blogs/aviwortzel/archive/2008/06/20/how-to-serialize-anonymous-delegates.aspx Я полагаю, что если это возможно, что они могут что-то использовать как это.

Но что, если у нас нет доступа к одной и той же сборке (например, Silverlight). Найти этот пост здесь: http://ayende.com/blog/4766/accessing-ravendb-from-silverlight

Объект IEnumerable<T> искал клиентскую или серверную сторону? Насколько конкретно мы можем получить серверную сторону в NOSQL, сужая результирующий набор, прежде чем отправлять его обратно на провод, не блокируя его одним уникальным идентификатором?

ОБНОВЛЕНИЕ: Я закончил электронную почту Айенде из RavenDB. Он любезно ответил на вопросы, которые у меня были (ниже):

Что вы можете сделать, это написать:

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

Это использует linq для определения вашего намерения, а затем отправляет запрос на сервер с использованием синтаксиса RavenDB. На сервере мы анализируем ваш запрос, а оптимизатор запросов проверяет, существует ли существующий индекс, который может ответить на этот запрос, а если нет, он создаст для вас временный индекс.

Если вы запросите этот временной индекс достаточно, RavenDB сделает его постоянным. Таким образом, самостоятельная оптимизация собственных операций.

Удалось ли вам использовать "из Silverlight"?

Мы полностью поддерживаем Silverlight.

Может ли RavenDB обрабатывать несколько серверных серверов?

Да. На самом деле у нас есть несколько клиентов, у которых есть > 500 индексов, без проблем.

КОНЕЦ ИНФОРМАЦИИ ИЗ Ayende at RavenDB

При проектировании языка запросов (то есть FindAll/where/delegate) mongo, похоже, немного справляется с этим через JSON... http://www.mongodb.org/display/DOCS/Indexes Хотел бы я знать об этом больше.

Звучит ближе: http://www.mongodb.org/display/DOCS/MapReduce

Интересный поток сериализации Сериализация анонимных делегатов в С#. Это не имеет прямого значения... но я просто пытаюсь немного подглядывать под капот, поэтому я больше знаю о возможностях.

Ответ 1

Я не уверен, что это применимо к NoSQL, но я реализовал шаблон Generic Repository с Raven DB и вот фрагмент.

Сначала я определил несколько интерфейсов

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

И это сокращение реализации

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

Пример использования

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

Пример теста для создания, который использует метод Find (FirstOrDefault) для 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);
}