支持Numeric或Guid Id属性,可以无缝工作。在这种情况下,RavenDB将自动将内部字符串ID转换为实体中显示的数字或Guid值,然后返回。
我存储了以下对象:
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 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
}
我创建了以下索引来创建投影:
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);
我得到了这个例外:
转换值时出错&#34; bs / cc0a65ae-dd36-4437-8a57-fa20b91eeef7&#34;输入&#39; System.Guid&#39;。路径&#39; Id&#39;。
问题:
这是由我的投影中的转换引起的,因为Id
是一个字符串而不是我的Guid。但是,将其删除将不会返回Id。我该怎么办?
我必须使用字符串构建"bs/" + r.BId.ToString()
来加载相关文档。有没有办法不必这样做?是否有某种功能可以为我解析doc标签?
是否有完全去除文档标记的通用方法?
我的约束。
我将生成Guid并且不能让RavenDb为我生成它。我知道文档ID实际上是字符串,但我真的需要使用我创建的Guid。我更愿意拥有我的实体的Id
属性。
我使用的是Raven.Client 1.0.972
答案 0 :(得分:6)
您可以使用MultiMap / Reduce Index实现此目的,但您需要一些hackery:
1)你需要减少使用字符串,而不是guids。您仍然可以在AB类中将这些值作为guid返回,我将在下面进行演示。
2)你不能调用你的AB类“Id”的第一个属性,因为raven会尝试将其翻译为“__document_id”。所以称之为“AId”,它会正常工作。
3)在映射阶段,您必须自己操纵字符串以去除文档密钥前缀。
这是一个将所有内容组合在一起的示例程序。这表明它确实有效,但我认为它也说明了为什么Ayende更喜欢字符串标识符,所以你不必处理这种混乱。
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; }
}
}
}
答案 1 :(得分:2)
您可以在保存时明确向RavenDB提供ID:
session.Store(doc, explicitIdValueString);
explicitIdValueString
可以是Guid字符串。此值将用于标识整个数据库中的文档,并且不会以类型标记名称为前缀。您还可以通过覆盖IDocumentStore.Conventions
上的约定来自定义标记名称或ID生成策略,例如FindTypeTagName
Func<Type, string>
。
答案 2 :(得分:2)
主要问题是虽然RavenDB可以处理客户端上的数字/整数,但是在服务器端,RavenDB使用字符串ID。
通常,不建议使用Guids /数字ID。
答案 3 :(得分:1)
假设您有用户并且您想为这些生成guid标识符。
new User { Id = "users/" + Guid.NewGuid().ToString("N") }
出于理智的目的,在文档中我急切地创建了密钥,我将它们设置为不可变的。
public class User
{
public User(Guid? guid = null)
{
IdPart = (guid ?? Guid.NewGuid()).ToString("N")
}
string IdPart { get; }
string Id => $"Users/{IdPart}"
有时,IdPart实际上是一把钥匙。假设我们有&#34; Users / abc&#34;。如果用户有项目。我将通常创建一个类似于:
的文档public class Project
{
public User(Guid? userId = null)
{
UserId = "Users/" + (guid ?? Guid.NewGuid()).ToString("N");
Id = $"{UserId}/project/"
}
请注意尾随project/
这将通知raven在斜杠后创建HiLo值。
此概念可用于轻松混合指定的标识符,自然标识符和序列/ hilo /身份键,同时提升可读标识符而不是1
。 1
是什么?但User/abc/project/1
,我可以告诉你那是什么。 abc
答案 4 :(得分:-1)
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
{
Id = Guid.Parse(r.Id.ToString().Split('/').Last()),
r.BId,
BName = b.Name
};
}
}