【问题标题】:Model one to many in RavenDb for better performance在 RavenDb 中为一对多建模以获得更好的性能
【发布时间】:2017-05-23 16:24:23
【问题描述】:

我正在接近文档数据库,我有点困惑如何映射文档关系,情况如下

public class Person
{
    public Person()
    {
    }
    public int Id { get; set; }
    public string Name { get;set;}
    public string Surname { get; set; }
    public DateTime? BirthDate { get; set; }
}


public class Car
{
    public Car() { }
    public int Id { get; set; }
    public string Name { get; set; }
    public int PersonId { get; set;}
}

例如,一个人拥有一辆或多辆汽车,我可以按以下方式查询数据库

public Car Get(int id)
    {
        Car car = null;
        using (IDocumentSession session = store.OpenSession())
        {
            car = session.Include<Car, Person>(x => x.PersonId).Load<Car>(id);
            bool isLoaded = session.Advanced.IsLoaded("people/" + car.PersonId); // true!
        }
        return car;
    }

一切都好,客户只提出一个请求,但如果我有一个人,我想展示他所有的汽车,我如何查询数据库来做一个请求? 我想我必须修改模型,将List&lt;int&gt; Cars 放入Person 以供参考他的汽车。 请注意,我不想在Person 文档中嵌入Cars,因为Cars 可以从其他文档中引用。

谢谢。

【问题讨论】:

    标签: c# relationship ravendb document-database


    【解决方案1】:

    您可以索引 Cars 集合并从索引中加载所有汽车。

    索引如下所示:

    public class CarIndex : AbstractIndexCreationTask<Car, CarView>
    {
        public CarIndex()
        {
            Map = cars => from car in cars
                          select new
                          {
                              car.Id,
                              car.Name,
                              car.PersonId,
                          };
        }
    }
    

    CarView 类与 Car 类相同,但可以进行更改以更好地满足索引需求。

    public class CarView
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int PersonId { get; set; }
    }
    

    您需要先执行索引才能使用它:

    new CarIndex().Execute(store);
    

    为某个人装载汽车如下所示:

    using (IDocumentSession session = store.OpenSession())
    {
        session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
        session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
        session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
        session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
        session.SaveChanges();
    }
    
    WaitForIndexing(store); // from RavenTestBase
    
    using (IDocumentSession session = store.OpenSession())
    {
        var resultsForId1 = session
            .Query<CarView, CarIndex>()
            .ProjectFromIndexFieldsInto<CarView>()
            .Where(x => x.PersonId == 1);
        Assert.Equal(2, resultsForId1.Count());
        var resultsForId2 = session
            .Query<CarView, CarIndex>()
            .ProjectFromIndexFieldsInto<CarView>()
            .Where(x => x.PersonId == 2);
        Assert.Equal(1, resultsForId2.Count());
    }
    

    如果您想在单个数据库请求中加载人员及其汽车,请使用延迟加载:

    var resultsForId1 = session
        .Query<CarView, CarIndex>()
        .ProjectFromIndexFieldsInto<CarView>()
        .Where(x => x.PersonId == 1).Lazily();
    var person = session.Advanced.Lazily.Load<Person>(1);
    
    var personValue = person.Value;
    var resultsValue = resultsForId1.Value;
    

    完整测试(需要 xunit 和 RavenDB.Tests.Helpers nugets):

    using Raven.Client;
    using Raven.Client.Indexes;
    using Raven.Tests.Helpers;
    using System;
    using System.Linq;
    using Xunit;
    
    namespace SO41547501Answer
    {
        public class SO41547501 : RavenTestBase
        {
            [Fact]
            public void SO41547501Test()
            {
                using (var server = GetNewServer())
                using (var store = NewRemoteDocumentStore(ravenDbServer: server))
                {
                    new CarIndex().Execute(store);
    
                    using (IDocumentSession session = store.OpenSession())
                    {
                        session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
                        session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
                        session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
                        session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
                        session.SaveChanges();
                    }
    
                    WaitForAllRequestsToComplete(server);
                    WaitForIndexing(store);
    
                    using (IDocumentSession session = store.OpenSession())
                    {
                        var resultsForId1 = session
                            .Query<CarView, CarIndex>()
                            .ProjectFromIndexFieldsInto<CarView>()
                            .Where(x => x.PersonId == 1);
                        Assert.Equal(2, resultsForId1.Count());
                        var resultsForId2 = session
                            .Query<CarView, CarIndex>()
                            .ProjectFromIndexFieldsInto<CarView>()
                            .Where(x => x.PersonId == 2);
                        Assert.Equal(1, resultsForId2.Count());
                    }
    
                    using (IDocumentSession session = store.OpenSession())
                    {
                        server.Server.ResetNumberOfRequests();
                        var resultsForId1 = session
                            .Query<CarView, CarIndex>()
                            .ProjectFromIndexFieldsInto<CarView>()
                            .Where(x => x.PersonId == 1).Lazily();
                        var person = session.Advanced.Lazily.Load<Person>(1);
    
                        var personValue = person.Value;
                        var resultsValue = resultsForId1.Value;
                        Assert.Equal("A", personValue.Name); // person data loaded
                        Assert.Equal("A", resultsValue.First().Name); // cars data loaded
                        Assert.Equal(1, server.Server.NumberOfRequests); // only one request sent to the server
                    }
                }
            }
        }
    
        public class CarIndex : AbstractIndexCreationTask<Car, CarView>
        {
            public CarIndex()
            {
                Map = cars => from car in cars
                              select new
                              {
                                  car.Id,
                                  car.Name,
                                  car.PersonId,
                              };
            }
        }
    
        public class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Surname { get; set; }
            public DateTime? BirthDate { get; set; }
        }
    
        public class Car
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int PersonId { get; set; }
        }
    
        public class CarView
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int PersonId { get; set; }
        }
    }
    

    【讨论】:

      【解决方案2】:

      你可以这样做:

      using (IDocumentSession session = store.OpenSession())
      {
          var carsForOne = session.Query<Car>()
                   .Include(x=>x.PersonId)
                   .Where(x=>x.PersonId == "people/1")
                   .ToList();
      
          var person = session.Load<Person>("people/1");
      }
      

      这只会产生一个数据库请求。

      【讨论】:

        猜你喜欢
        • 2015-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-13
        • 1970-01-01
        • 1970-01-01
        • 2022-10-08
        • 1970-01-01
        相关资源
        最近更新 更多