在 RavenDB 中作为 Id 的 Guid [英] Guid as Id in RavenDB

查看:38
本文介绍了在 RavenDB 中作为 Id 的 Guid的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

RavenDb 文档 指出:

支持数字或 Guid Id 属性并且可以无缝工作.在这种情况下,RavenDB 会自动将内部字符串 ID 转换为实体中显示的数字或 Guid 值并返回.

Numeric or Guid Id properties are supported and will work seamlessly. In this case, RavenDB will automatically make the translation between the inner string ID to the numeric or Guid value shown in the entity and back.

我存储了以下对象:

class A
{
    public Guid Id { get; set; }
    public Guid BId { get; set; }
}

class B
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

然后我创建了以下投影:

I have then created the following projection:

class AB
{
    public Guid Id { get; set; }       // This should be the Id of A
    public Guid BId { get; set; }      // This should be the Id of B
    public string BName { get; set; }  // This should be the name of B
}

我创建了以下索引来创建投影:

I have created the following index to create the projection:

class MyIndex : AbstractIndexCreationTask<AB>
{
    public MyIndex()
    {
        Map = docs =>
            from d in docs
            select new
            {
                d.Id,
                d.BId,
                BName = string.Empty
            };

        TransformResults = (database, results) =>
            from r in results
            let b = database.Load<B>("bs/" + r.BId.ToString())
            select new
            {
                r.Id,
                r.BId,
                BName = b.Name
            };
    }
}

当我使用以下查询时:

session.Query<AB, MyIndex>().FirstOrDefault(t => t.Id == guid);

我收到此异常:

将值bs/cc0a65ae-dd36-4437-8a57-fa20b91eeef7"转换为类型System.Guid"时出错.路径Id".

Error converting value "bs/cc0a65ae-dd36-4437-8a57-fa20b91eeef7" to type 'System.Guid'. Path 'Id'.

问题:

  1. 这是由我的投影中的转换引起的,因为 Id 是那里的字符串,不再是我的 Guid.但是,省略它不会返回 Id.我必须做什么?

  1. It is caused by the conversion in my projection since the Id is a string there and not my Guid anymore. However, leaving it out will not return the Id. What must I do?

我必须使用字符串构建 "bs/" + r.BId.ToString() 来加载相关文档.有没有办法不必这样做?是否有某种功能可以为我解析 doc 标签?

I have to use the string building "bs/" + r.BId.ToString() to load the related doc. Is there a way not having to do this? Is there some sort of function that would resolve the doc tag for me?

是否有一种通用的方法可以完全去除文档标签?

Is there a generic way to strip out the document tag altogether?

我的约束.

我将生成 Guid,不能让 RavenDb 为我生成它.我知道实际上文档 ID 是字符串,但我确实需要使用我创建的 Guid.我更愿意拥有我的实体的 Id 属性.

I will generate the Guid and cannot let RavenDb generate it for me. I know that the Document ID in reality is string, but I really need to use a Guid that I create. I would prefer to own the Id property of my entities.

我使用的是 Raven.Client 1.0.972

I'm using Raven.Client 1.0.972

推荐答案

您可以使用 MultiMap/Reduce Index 来实现这一点,但您需要一些技巧:

You can achieve this using a MultiMap/Reduce Index, but you will need some hackery:

1) 您需要减少使用字符串,而不是 guid.您仍然可以在 AB 类中将这些值作为 guid 取回,我将在下面演示.

1) You will need to reduce using strings, not guids. You can still get the values back as guids in your AB class, as I will demonstrate below.

2) 您不能将 AB 类的第一个属性称为Id",因为 raven 会尝试将其转换为__document_id".所以称之为AId",它会正常工作.

2) You can't call the first property of your AB class "Id", as raven will try to translate it to "__document_id". So call it "AId" and it will work fine.

3) 在映射阶段,您必须自己操作字符串以去除文档键前缀.

3) In the mapping phase, you have to manipulate the strings yourself to strip off the document key prefix.

这是一个将所有内容组合在一起的示例程序.这表明它确实有效,但我认为这也说明了为什么 Ayende 更喜欢字符串标识符,这样您就不必处理这种混乱.

Here's a sample program that puts it all together. This demonstrates that it does indeed work, but I think it also shows why Ayende prefers string identifiers so you don't have to deal with this kind of mess.

using System;
using System.Linq;
using Raven.Client.Document;
using Raven.Client.Indexes;

namespace RavenScratchTest
{
  class Program
  {
    static void Main()
    {
      var documentStore = new DocumentStore { Url = "http://localhost:8080" };
      documentStore.Initialize();
      IndexCreation.CreateIndexes(typeof(Program).Assembly, documentStore);

      using (var session = documentStore.OpenSession())
      {
        var b = new B { Id = Guid.NewGuid(), Name = "Foo" };
        var a = new A { Id = Guid.NewGuid(), BId = b.Id };

        session.Store(a);
        session.Store(b);

        session.SaveChanges();
      }

      using (var session = documentStore.OpenSession())
      {
        var a = session.Query<A>().Customize(x => x.WaitForNonStaleResults()).First();
        var b = session.Query<B>().Customize(x => x.WaitForNonStaleResults()).First();

        Console.WriteLine("A:  Id = {0}", a.Id);
        Console.WriteLine("   BId = {0}", a.BId);
        Console.WriteLine();
        Console.WriteLine("B:  Id = {0}", b.Id);
        Console.WriteLine("  Name = {0}", b.Name);
        Console.WriteLine();

        var guid = a.Id;
        var ab = session.Query<AB, MyIndex>().Customize(x => x.WaitForNonStaleResults())
          .FirstOrDefault(t => t.AId == guid);

        if (ab == null)
          Console.WriteLine("AB: NULL");
        else
        {
          Console.WriteLine("AB:  AId = {0}", ab.AId);
          Console.WriteLine("   BId = {0}", ab.BId);
          Console.WriteLine("   BName = {0}", ab.BName);
          Console.WriteLine();
        }
      }

      Console.WriteLine();
      Console.WriteLine("Done.");
      Console.ReadLine();
    }
  }

  class A
  {
    public Guid Id { get; set; }
    public Guid BId { get; set; }
  }

  class B
  {
    public Guid Id { get; set; }
    public string Name { get; set; }
  }

  class AB
  {
    public Guid AId { get; set; }
    public Guid BId { get; set; }
    public string BName { get; set; }
  }

  class MyIndex : AbstractMultiMapIndexCreationTask<MyIndex.ReduceResult>
  {
    public MyIndex()
    {
      AddMap<A>(docs => from a in docs
                select new
                {
                  AId = a.Id.ToString().Split('/')[1],
                  a.BId,
                  BName = (string)null
                });

      AddMap<B>(docs => from b in docs
                select new
                {
                  AId = (string)null,
                  BId = b.Id.ToString().Split('/')[1],
                  BName = b.Name
                });

      Reduce = results => from result in results
                group result by result.BId
                into g
                select new
                  {
                    g.FirstOrDefault(x => x.AId != null).AId,
                    BId = g.Key,
                    g.FirstOrDefault(x => x.BName != null).BName
                  };
    }

    internal class ReduceResult
    {
      public string AId { get; set; }
      public string BId { get; set; }
      public string BName { get; set; }
    }
  }
}

这篇关于在 RavenDB 中作为 Id 的 Guid的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆