учитывая список объектов, использующих C #, поместите их в ravendb, не зная, какие из них уже существуют - PullRequest
3 голосов
/ 19 октября 2011

Дано 1000 документов со сложной структурой данных.например, для класса Car, который имеет три свойства: Make и Model и одно свойство Id.

Какой самый эффективный способ в C # передать эти документы в raven db (предпочтительно в пакете) без необходимости запрашиватьКоллекция воронов индивидуально, чтобы найти, что обновить, а что вставить.На данный момент я должен идти так.Что совершенно неэффективно. примечание: _session - это оболочка для IDocumentSession , где Commit вызывает SaveChanges и добавляет вызовы Store .

    private void PublishSalesToRaven(IEnumerable<Sale> sales)
    {
        var page = 0;
        const int total = 30;
        do
        {
            var paged = sales.Skip(page*total).Take(total);
            if (!paged.Any()) return;
            foreach (var sale in paged)
            {
                var current = sale;
                var existing = _session.Query<Sale>().FirstOrDefault(s => s.Id == current.Id);
                if (existing != null)
                    existing = current;
                else
                    _session.Add(current);
            }
            _session.Commit();
            page++;
        } while (true);
    }

Ответы [ 3 ]

3 голосов
/ 19 октября 2011

Ваш код сеанса, похоже, не соответствует API RavenDB (у нас нет Add или Commit). Вот как вы это делаете в RavenDB

private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
    sales.ForEach(session.Store);
    session.SaveChanges();
}
2 голосов
/ 19 октября 2011

Ваш пример кода не работает вообще.Основная проблема заключается в том, что вы не можете просто переключить ссылки и ожидать, что RavenDB распознает, что:

if (existing != null)
    existing = current;

Вместо этого вы должны обновлять каждое свойство один за другим:

existing.Model = current.Model;
existing.Make = current.Model;

Таким способом вы можете облегчить отслеживание изменений в RavenDB и многих других средах (например, NHibernate).Если вы не хотите писать этот интересный фрагмент кода, я рекомендую использовать AutoMapper:

existing = Mapper.Map<Sale>(current, existing);

Другая проблема с вашим кодом заключается в том, что вы используете Session.Query, где вам следует использовать Session.Load. Помните: если вы запрашиваете документ по его идентификатору, вы всегда будете использовать Load! Основное отличие состоит в том, что один использует локальный кэш, а другой нет (то же самое относится к эквивалентным методам NHibernate).

Хорошо, теперь я могу ответить на ваш вопрос: если я вас правильно понимаю, вы хотите сохранить несколько экземпляров Sale в вашу базу данных, в то время как они должны быть либо добавлены, если они не существуют, либо обновлены, еслиони существовали.Правильно?Один из способов - исправить ваш пример кода с помощью приведенных выше советов и позволить ему работать.Однако это выдаст один ненужный запрос (Session.Load (существующий идентификатор)) для каждой итерации.Вы можете легко избежать этого, если настроите индекс, который выбирает все идентификаторы всех документов в вашей Sales-collection.Перед тем, как перейти к вашим элементам, вы можете загрузить все существующие идентификаторы.

Однако я хотел бы знать, что вы на самом деле хотите сделать.Какой у вас домен / сценарий использования?

0 голосов
/ 20 октября 2011

Это то, что работает для меня прямо сейчас. Примечание: метод InjectFrom происходит из Omu.ValueInjecter (пакет nuget)

    private void PublishSalesToRaven(IEnumerable<Sale> sales)
    {
        var ids = sales.Select(i => i.Id);
        var existingSales = _ravenSession.Load<Sale>(ids);
        existingSales.ForEach(s => s.InjectFrom(sales.Single(i => i.Id == s.Id)));

        var existingIds = existingSales.Select(i => i.Id);
        var nonExistingSales = sales.Where(i => !existingIds.Any(x => x == i.Id));
        nonExistingSales.ForEach(i => _ravenSession.Store(i));

        _ravenSession.SaveChanges();
    }
...