簡體   English   中英

在RavenDb中一對多建模以獲得更好的性能

[英]Model one to many in RavenDb for better performance

我正在接近文檔數據庫,但在以下情況下我有點困惑如何映射文檔關系

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<int> Cars in Person以供參考。 請注意,我不想在“ Person文檔中嵌入“ Cars ,因為可以從其他文檔中引用“ Cars

謝謝。

您可以為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; }
    }
}

您可以這樣做:

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");
}

這僅發出一個數據庫請求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM