使用 C# 给定一个对象列表,将它们推送到 ravendb,而不知道哪些对象已经存在

发布于 2024-12-10 10:09:49 字数 968 浏览 0 评论 0原文

给定 1000 个具有复杂数据结构的文档。例如,一个 Car 类具有三个属性(Make 和 Model)以及一个 Id 属性。

C# 中将这些文档推送到 raven db(最好是批量)的最有效方法是什么,而无需单独查询 raven 集合来查找要更新的内容和要插入的内容。目前我必须像这样走。这是完全低效的。 注意:_session 是 IDocumentSession 上的一个包装器,其中 Commit 调用 SaveChanges 并 Add 调用 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);
    }

Given 1000 documents with a complex data structure. for e.g. a Car class that has three properties, Make and Model and one Id property.

What is the most efficient way in C# to push these documents to raven db (preferably in a batch) without having to query the raven collection individually to find which to update and which to insert. At the moment I have to going like so. Which is totally inefficient.
note : _session is a wrapper on the IDocumentSession where Commit calls SaveChanges and Add calls 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);
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

安静 2024-12-17 10:09:49

您的会话代码似乎无法使用 RavenDB api 进行跟踪(我们没有 AddCommit)。
以下是在 RavenDB 中执行此操作的方法

private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
    sales.ForEach(session.Store);
    session.SaveChanges();
}

Your session code doesn't seem to track with the RavenDB api (we don't have Add or Commit).
Here is how you do this in RavenDB

private void PublishSalesToRaven(IEnumerable<Sale> sales)
{
    sales.ForEach(session.Store);
    session.SaveChanges();
}
清风疏影 2024-12-17 10:09:49

您的代码示例根本不起作用。主要问题是,您不能只是切换引用并期望 RavenDB 认识到这一点:

if (existing != null)
    existing = current;

相反,您必须一一更新每个属性:

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

这是您可以在 RavenDB 和许多其他框架中促进更改跟踪的方式(例如NHibernate)。如果您想避免编写这段无趣的代码,我建议使用 AutoMapper:

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

代码的另一个问题是您在应该使用 Session.Load 的地方使用了 Session.Query。 记住:如果您通过 ID 查询文档,您将始终需要使用 Load!
主要区别在于,一个使用本地缓存,另一个不使用(这同样适用于等效的 NHibernate 方法)。

好的,现在我可以回答你的问题了:
如果我理解正确,您希望将一堆销售实例保存到数据库中,如果它们不存在,则应添加它们,如果存在,则应更新它们。正确的?
一种方法是使用上面的提示更正示例代码并使其正常工作。但是,这将为每次迭代发出一个不必要的请求 (Session.Load(existingId))。如果您设置一个索引来选择 Sales 集合中所有文档的所有 Id,则可以轻松避免这种情况。在循环访问项目之前,您可以加载所有现有的 ID。

不过,我想知道你到底想做什么。您的领域/用例是什么?

Your code sample doesn't work at all. The main problem is that you cannot just switch out the references and expect RavenDB to recognize that:

if (existing != null)
    existing = current;

Instead you have to update each property one-by-one:

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

This is the way you can facilitate change-tracking in RavenDB and many other frameworks (e.g. NHibernate). If you want to avoid writing this uinteresting piece of code I recommend to use AutoMapper:

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

Another problem with your code is that you use Session.Query where you should use Session.Load. Remember: If you query for a document by its id, you will always want to use Load!
The main difference is that one uses the local cache and the other not (the same applies to the equivalent NHibernate methods).

Ok, so now I can answer your question:
If I understand you correctly you want to save a bunch of Sale-instances to your database while they should either be added if they didn't exist or updated if they existed. Right?
One way is to correct your sample code with the hints above and let it work. However that will issue one unnecessary request (Session.Load(existingId)) for each iteration. You can easily avoid that if you setup an index that selects all the Ids of all documents inside your Sales-collection. Before you then loop through your items you can load all the existing Ids.

However, I would like to know what you actually want to do. What is your domain/use-case?

千纸鹤 2024-12-17 10:09:49

这就是现在对我有用的方法。注意: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();
    }

This is what works for me right now. Note: The InjectFrom method comes from Omu.ValueInjecter (nuget package)

    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();
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文