有NOSQL数据层设计模式吗?

发布于 2024-11-27 00:57:58 字数 2378 浏览 0 评论 0原文

我已经看到了一些关于此的想法,例如使用 Get 和 Put 代替创建、更新、插入、删除 (CRUD)。那挺好的。然而,我还没有看到太多关于如何处理复杂性的内容。有人告诉我,“只需为您需要的每种查询类型编写一个方法”。

大多数 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 对象是在客户端还是服务器端搜索的?在通过线路将结果集发送回之前,我们可以在 NOSQL 中的服务器端缩小结果集的范围,而不将其锁定到一个唯一的 ID,具体如何?

更新:我最终从 RavenDB 给 Ayende 发了电子邮件。他亲切地回答了我的问题(如下):

你能做的就是写:

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

这使用 linq 来确定您的意图,然后使用 RavenDB 的语法将查询发送到服务器。在服务器上,我们分析您的查询,查询优化器检查是否存在可以回答该查询的现有索引,如果不存在,它将为您创建一个临时索引。

如果您对该临时索引的查询足够多,RavenDB 会将其永久化。因此,自我优化自己的运营。

您对“来自 Silverlight”用例的了解是否深入?

我们完全支持 Silverlight。

RavenDB 可以处理多个索引服务器端吗?

是的。事实上,我们有一些客户拥有 > 500 个索引运行没有问题。

RavenDB 的 Ayende 信息结束

在设计查询语言(即 FindAll / where / delegate)时,mongo 似乎通过 JSON 实现了一些... http://www.mongodb.org/display/DOCS/Indexes 我希望我了解更多。

这听起来更接近: http://www.mongodb.org/display/DOCS/MapReduce

关于序列化的有趣主题序列化匿名委托C#。这并不直接相关......但我只是想稍微了解一下,以便我更多地了解潜力。

I've seen a few ideas on this like instead of like Create, Update, Insert, Delete (CRUD) use Get and Put. That's good. However, I haven't seen much yet on how to deal with complexity. I've been told, "just write a method for every query type that you need".

Most of NOSQL seems okay to me until I start thinking about qualifiers (a where clause) -- there could be so many variations. Is there already a good scheme for implementing qualifiers in a sensible way, using just method names & argument conventions? Perhaps there's some kind of verb / noun scheme that works well, but which isn't a language in its own right.

I'm not after the 'right' answer... I'm hoping that there are a few schools of thought that I could learn from.

Found this blog post from the maker of RavenDB: http://ayende.com/blog/4562/ravendb-index-management

Can we implement more than one index on a class?

I even found that it might be possible to serialize anonymous delegates http://blogs.microsoft.co.il/blogs/aviwortzel/archive/2008/06/20/how-to-serialize-anonymous-delegates.aspx I suppose if this is possible, that they might use something like this.

But what if we don't have access to the same assembly (e.g. Silverlight). Found this post here:
http://ayende.com/blog/4766/accessing-ravendb-from-silverlight

Is the IEnumerable<T> object searched client-side or server-side? How specific can we get server side in NOSQL in narrowing down the result set before sending it back over the wire, without locking it to one unique id?

UPDATE: I ended up emailing Ayende from RavenDB. He kindly answered the questions that I had (below):

What you can do is write:

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

This uses linq to figure out your intent, and then sends the query to the server using RavenDB's syntax. On the server, we analyze your query, and the query optimizer checks to see if there is an existing index that can answer this query, and if there isn't, it will create a temporary index for you.

If you query that temporary index enough, RavenDB will make it permanent. Thus, self optimizing its own operations.

Did you get very far with the "from Silverlight" use case?

We are fully supporting Silverlight.

Can RavenDB handle more than one index server side?

Yes. In fact, we have some customers that have > 500 indexes running with no issues.

END OF INFO FROM Ayende at RavenDB

On designing a query language (i.e. FindAll / where / delegate), mongo seem to achieve a little of this via JSON... http://www.mongodb.org/display/DOCS/Indexes I wish I knew more about it.

This sounds closer: http://www.mongodb.org/display/DOCS/MapReduce

An interesting thread on serializing Serializing anonymous delegates in C#. It's not directly relevant... but I am just trying to look under the hood a little so I know more about potentials.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

森林很绿却致人迷途 2024-12-04 00:57:58

我不确定这是否适用于 NoSQL,但我使用 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) 方法进行断言

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

I am not sure this is applicable to NoSQL, but I implemented a Generic Repository pattern with Raven DB and here is a snippet.

First, I defined a few 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);
}

And this is a shorten implementation

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

Usage sample

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

Sample test for create, which use Find (FirstOrDefault) method for 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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文