C# 为什么Raven会为我的新文档生成一个已经存在的文档Id?

C# 为什么Raven会为我的新文档生成一个已经存在的文档Id?,c#,ravendb,C#,Ravendb,为什么这段代码(试图)用第二个对象覆盖我的第一个对象?我的第一个对象的Id是“StringBasedIdClasses/1”,而第二个对象没有提供Id,所以Raven应该生成一个未使用的Id,不是吗 var quickStore = new EmbeddableDocumentStore() { RunInMemory = true }; quickStore.Initialize(); quickStore.RegisterListener(new DocumentConversionL

为什么这段代码(试图)用第二个对象覆盖我的第一个对象?我的第一个对象的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
 }

所有内容都使用文档存储的一个当前实例。这看起来很基本,所以一定错过了一些简单的东西。

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

好的,部分答案是Thomas所说的,但更具体地说,RavenDb完全忽略了您手动插入的ID。要执行批量导入(例如,像我这样从旧系统到新系统的数据迁移),您需要执行以下操作:

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

    session.Store(new {Id = "Raven/Hilo/{yourcollectionname}", Max = newMaxValue});
    session.SaveChanges(); 
    
  • 现在,当您初始化新存储时,将使用正确的hilo值


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

    您没有让RavenDB在第一个测试上生成Id。看起来它按预期工作。不……这是我的观点。我必须从上一个测试批量导入一些项目ious系统,已经有我们需要使用的Id。这是在检测到问题时的简化版本,无论我提供Id还是Raven生成Id-它应该知道已经存在的Id!没有“按预期工作”的方法。您正在指定Id,该Id正常工作。只需在导入完成后手动更新HiLo。您还可以使用
    session.Store(stringIdText,“StringBasedIdClasses/”)
    用您想要的Id替换
    当然我已经阅读了有关此的文档。那么这些策略是否不兼容?因为我知道创建Id的不同方法,但我从未看到过暗示它们不能一起使用的注释。例如,在SQL server中,不要导入带有Specific的数据ic ID我将使用一个标识插入,导入后我将关闭它。在允许默认策略继续之前,如何使用已知ID的数据为raven存储种子?