为什么Raven会为我的新文档生成已存在的文档ID?

时间:2014-05-29 14:55:02

标签: c# ravendb

为什么这段代码(尝试)用第二个对象覆盖我的第一个对象?我的第一个对象专门有一个ID为" StringBasedIdClasses / 1",而第二个对象没有提供Id,所以Raven应该生成一个未使用的Id不应该呢?

 var quickStore = new EmbeddableDocumentStore() { RunInMemory = true };
 quickStore.Initialize();
 quickStore.RegisterListener(new DocumentConversionListener()).RegisterListener(new DocumentStoreListener());

 using (var session = quickStore.OpenSession())
 {
      session.Advanced.UseOptimisticConcurrency = true;
      var stringIdTest = new StringBasedIdClass()
      {
           Id = "StringBasedIdClasses/1",
           Name = "StringItem1"
      };

      session.Store(stringIdTest);
      session.SaveChanges();
 }

 using (var session = quickStore.OpenSession())
 {
      session.Advanced.UseOptimisticConcurrency = true;
      var stringIdTest = new StringBasedIdClass()
      {
           Name = "DidIReplaceYou"
      };

      session.Store(stringIdTest);
      session.SaveChanges();//This fails with a ConcurrencyViolation as I use OptimisticConcurrency and have Etag support on my objects
 }

一切都在使用文档存储的一个当前实例。这似乎很基本,所以一定要错过一些简单的东西。

2 个答案:

答案 0 :(得分:7)

好的,答案部分是托马斯所说的,但更具体地说,RavenDb完全忽略了你手动插入的ID。为了进行批量导入(比如从旧系统到新系统的数据迁移,我需要执行以下操作:

  1. 确保处理连接到该数据库的任何文档存储(通常这意味着,没有运行您的应用程序)
  2. 批量导入系统,自行设置ID(您有责任确保不覆盖任何现有记录,但可以使用乐观并发和etags)
  3. 在导入结束时,使用以下代码将集合的hilo(基本上是新ID的起点)设置为高于系统中现在最高ID的值:

    session.Store(new {Id = "Raven/Hilo/{yourcollectionname}", Max = newMaxValue});
    session.SaveChanges(); 
    
  4. 现在初始化新商店时,将使用正确的hilo值。

  5. 请注意,使用内存版本的EmbeddableDocumentStore无法模拟此过程,因为您每次打开商店时实际上都会创建一个全新的服务器实例。因此,如果您尝试使用现有/非现有记录的已知ID进行集成测试,则必须让Raven选择ID而不将它们设置在您自己的对象中。这应该可以正常工作,因为你的新内存存储总是从1开始。为确保隔离我的测试,我为每次测试开了一个新商店。

答案 1 :(得分:2)

RavenDB的HiLo密钥生成器并不知道StringBasedIdClasses/1已在使用中,因此它会将其分配给您的第二个文档。有关详细信息,请参阅Document IDs generation strategies