2017-01-09 21 views
1

Я подхожу к документу базы данных, и я немного смущен, как сопоставить отношения документов, в ситуации, как следоватьмодель один ко многим в RavenDb для лучшей производительности

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

и это все в порядке, клиент делает только один запрос, но если у меня есть человек, и я хочу, чтобы показать все свои автомобили, как я могу запрашиваю db сделать только запрос? Я думаю, что я должен изменить модель, поставив List<int> Cars в Person для справки о его машинах. Обратите внимание, что я не хочу вставлять Cars в документ Person, потому что Cars можно ссылаться на другой документ.

Спасибо.

ответ

3

Вы можете указать коллекцию автомобилей и загрузить все автомобили из индекса.

Индекс будет выглядеть следующим образом:

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

Carview идентичен классу автомобиля, но может быть изменен, чтобы лучше соответствовать потребностям индексации.

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

Это делают только один запрос дб.