我应该如何从每日Feed中更新多个RavenDB文档?

时间:2012-06-14 09:27:27

标签: ravendb ravenhq

我正在使用RavenDB来保存数千个文档。数据来自每日xml feed,我将通过运行C#控制台应用程序来更新。下面是处理订阅源以使数据库与任何更改保持同步的代码。我遇到了很多问题,所以我想知道我是否采取了错误的策略。以下是一些需要注意的重要事项。

  1. 新商品可能已添加到Feed中,现有商品可能已添加 已经改变,所以每次运行我想要添加或更新 文件取决于它是否是新的。
  2. xml Feed不包含对我的RavenDB ID的任何引用,只包含每个项目的内部键。所以在检索现有的时候 要更新的文档我只能通过检查“SourceID”来做到这一点 文件上的财产。
  3. 我正在使用“take”一次仅使用500个文档,部分原因是因为我的数据库限制为1000个文档,部分原因是因为没有 Take()我似乎只能检索128个文档。
  4. 就目前而言,这段代码会出现“会话中不能超过30次更新”错误,我想因为每次我尝试 从dbItems中检索它实际命中的现有记录 数据库再次。
  5. 我可以通过调用项目上的ToList()来解决上面(4)中的问题,但如果我这样做,那么当我调用时,现有项目不会更新 session.SaveChanges()(我想象这就像断开连接 记录)。
  6. 任何人都可以给我一些指示吗?

            public void ProcessFeed(string rawXml)
            {
                XDocument doc = XDocument.Parse(rawXml);
                var items = ExtractItemsFromFeed(doc).OrderBy(x => x.SourceId).Take(500);
                using (IDocumentSession session = _store.OpenSession())
                {
                    var dbItems = session.Query<AccItem>().OrderBy(x => x.SourceId).Take(500);
                    foreach (var item in items)
                    {
                        var existingRecord = dbItems.SingleOrDefault(x => x.SourceId == item.SourceId);
                        if (existingRecord == null)
                        {
                            session.Store(item);
                            _logger.Info("Saved new item {0}.", item.ShortName);
                        }
                        else
                        {
                            // update just one field for now
                            existingRecord.Village = item.Village;
                            _logger.Info("Updated item {0}.", item.ShortName);
                        }
                    }
                    session.SaveChanges();
                }            
            }
    

1 个答案:

答案 0 :(得分:0)

以下是我最终得到的代码。我认为原始版本的最初问题只是我试图为每个项目使用相同的会话,打破30限制。

通过TekPub屏幕录像中的屏幕上的一些代码提示我通过将整个过程批量处理成15组来修复此问题(允许一次读取和一次写入,因此每批次总共30次请求)。这很慢,但并不像我预期的那么慢。我希望一次可能有10,000条记录,所以我只是把它留下来,直到它完成为止。

public void ProcessFeed(string rawXml)
{
    XDocument doc = XDocument.Parse(rawXml);
    var items = ExtractItemsFromFeed(doc).OrderBy(x => x.SourceId);
    int numberOfItems = items.Count;
    int batchSize = 15;
    int numberOfBatchesRequired = numberOfItems / batchSize;
    int numberOfBatchesProcessed = 0;
    int numberOfItemsInLastBatch = numberOfItems - (numberOfBatchesRequired * batchSize); 
    for (var i = 0;i <= numberOfBatchesRequired;i++)
    {
        using (IDocumentSession session = _store.OpenSession())
        {
            var numberOfItemsProcessedSoFar = numberOfBatchesProcessed * batchSize;
            var numberOfItemsRemaining = numberOfItems - numberOfItemsProcessedSoFar;
            int itemsToTake = 15;
            if (numberOfItemsRemaining > 0 && numberOfItemsRemaining < 15)
            itemsToTake = numberOfItemsRemaining;
            foreach (var item in items.Skip(numberOfItemsProcessedSoFar).Take(itemsToTake))
            {
            var existingRecords = session.Query<AccItem>().Where(x => x.SourceId == item.SourceId).ToList();
            if (!existingRecords.Any())
            {
                session.Store(item);
                _logger.Info("Saved new item {0}.", item.ShortName);
            }
            else
            {
                if (existingRecords.Count() > 1)
                _logger.Warn("There's more than one item in the database with the sourceid {0}", item.SourceId);
                existingRecords.First().Village = item.Village;
                _logger.Info("Updated item {0}.", item.ShortName);
            }
            session.SaveChanges();
            }
        }            
        numberOfBatchesProcessed++;
    }
}