鉴于文档数据库(例如RavenDB)是非关系数据库,如何避免重复多个文档具有相同数据的数据?如果可以复制该数据,该如何维护?

最佳答案

使用文档数据库,您必须在某种程度上复制数据。该程度取决于您的系统和用例。

例如,如果我们有一个简单的博客和用户聚合,则可以将它们设置为:

  public class User
  {
    public string Id { get; set; }
    public string Name  { get; set; }
    public string Username  { get; set; }
    public string Password  { get; set; }
  }

  public class Blog
  {
     public string Id  { get; set; }
     public string Title  { get; set; }

     public class BlogUser
     {
       public string Id  { get; set; }
       public string Name  { get; set; }
     }
  }

在此示例中,我在Blog类中嵌套了BlogUser类,并具有与Blog关联的用户集合的Id和Name属性。我包括了这些字段,因为它们是Blog类感兴趣的唯一字段,在显示博客时不需要知道用户的用户名或密码。

这些嵌套的类将取决于您的系统用例,因此您必须仔细设计它们,但总体思路是尝试设计可通过一次读取就可以从数据库加载的聚合,它们将包含所需的所有数据。显示或操纵它们。

然后,这引发了一个问题:当User.Name被更新时会发生什么。

对于大多数文档数据库,您将必须加载属于更新的User的Blog的所有实例,并更新Blog.BlogUser.Name字段,然后将所有实例保存回数据库中。

Raven支持更新的设置功能,因此略有不同,因此您可以针对RavenDB运行单个更新,这将使用户博客的BlogUser.Name属性更新,而不必单独加载和更新它们。

在RavenDB中(手动方式)对所有博客进行更新的代码为:
  public void UpdateBlogUser(User user)
  {
    var blogs = session.Query<Blog>("blogsByUserId")
                  .Where(b.BlogUser.Id == user.Id)
                  .ToList();

    foreach(var blog in blogs)
       blog.BlogUser.Name == user.Name;

    session.SaveChanges()
  }

我以示例为例添加了SaveChanges。 RavenDB客户端使用工作单元模式,因此这实际上应该在此方法之外的某个地方发生。

09-07 19:54
查看更多