Вначале я хотел бы упомянуть, что я новичок в каких-либо базах данных № Sql. Думаю, я мог неправильно понять концепцию индексов в RavenDb.
В моем приложении у меня есть набор документов, представляющих историю заправки автомобилей (с дочерней коллекцией маршрутов, взятых на этой заправке). Упрощенная версия выглядит так:
public class Fuel
{
public decimal? VolumeUsed { get; set; }
public decimal CostPerLitre { get; set; }
public decimal? TotalDistance { get; set; }
public IList<Route> Routes { get; set; }
}
public class Route
{
public string StartingAddress { get; set; }
public IList<Stop> Stops { get; set; }
}
Документы в коллекции не будут часто изменяться, поэтому я решил поместить все вычисления в базу данных, а не рассчитывать все на лету по каждому запросу. Но я не думаю, что в этом документе должны быть дополнительные поля расчета, поскольку они будут зависеть только от существующих значений, а не предоставлены пользователем. И я подумал о Map index
- очень хорошем способе выполнения вычислений (и, возможно, агрегирования в будущем) каждый раз, когда документ вставляется или изменяется.
Я создал другой класс для индекса
public class FuelCalculated
{
public decimal? VolumeUsed { get; set; }
public decimal CostPerLitre { get; set; }
public decimal? TotalDistance { get; set; }
public decimal? AverageFuelConsumption { get; set; }
public decimal? TotalCost { get; set; }
public IList<RouteCalculated> Routes { get; set; }
}
public class RouteCalculated
{
public string StartingAddress { get; set; }
public IList<Stop> Stops { get; set; }
public decimal TotalDistance { get; set; }
public decimal AverageFuelConsumption { get; set; }
}
и определение индекса:
public class FuelCalculatedIndex : AbstractIndexCreationTask<Fuel, FuelCalculated>
{
public FuelCalculatedIndex()
{
Map = fuels =>
fuels.Select(f => new FuelCalculated()
{
AverageFuelConsumption = (f.VolumeUsed * 100) / f.TotalDistance,
Routes = f.Routes.Select(r => new RouteCalculated()
{
StartingAddress = r.StartingAddress,
Stops = r.Stops,
TotalDistance = r.Stops.Sum(s => s.Distance),
AverageFuelConsumption = r.Stops.Sum(s => s.AverageFuelConsumption * s.Distance) / r.Stops.Sum(s => s.Distance),
}).ToList(),
TotalCost = f.VolumeUsed * f.CostPerLitre,
TotalDistance = f.TotalDistance,
VolumeUsed = f.VolumeUsed,
});
StoreAllFields(FieldStorage.Yes);
}
}
На данный момент меня не волнует объем индекса - я хочу иметь все необходимое для отображения, чтобы запросы не переходили к исходному документу.
Теперь, когда я запрашиваю документы в коде, я получаю нулевые результаты (или 0 для полей, не допускающих значения NULL) в каждом вычисляемом поле:
using (var session = documentStore.OpenAsyncSession())
{
return await session
.Query<FuelCalculated, FuelCalculatedIndex>()
.ToListAsync();
}
Возвращено JSON:
{
"volumeUsed":28.04,
"costPerLitre":4.93,
"totalDistance":467.3,
"totalCost":null, <----
"averageFuelConsumption":null, <----
"routes":[
{
"startingAddress":"Address 1",
"stops":[
{
"address":"Address 2",
"distance":351.0,
"averageFuelConsumption":6.0
}
],
"totalDistance":0, <----
"totalAverageFuelConsumption":0 <----
},
{
"startingAddress":"Address 3",
"stops":[
{
"address":"Address 4",
"distance":116.3,
"averageFuelConsumption":7.0
}
],
"totalDistance":0, <----
"totalAverageFuelConsumption":0 <----
}
]
}
Я очень запутался, когда попробовал простой запрос RavenDb в Raven.Studio
, и он вернул правильные значения
from index 'FuelCalculatedIndex'
select TotalCost
Так что, похоже, проблема заключается в коде C#. Что я делаю не так?
ОБНОВЛЕНИЕ
Я только что попытался запустить необработанный запрос в C#:
await session
.Advanced.AsyncRawQuery<FuelCalculated>("from index 'FuelCalculatedIndex' select TotalCost")
.ToListAsync();
Удивительно, но это работает.