Самый простой способ сгладить документ с представлением в RavenDB - PullRequest
5 голосов
/ 27 марта 2012

Учитывая следующие классы:

public class Lookup
{
    public string Code { get; set; }
    public string Name { get; set; }
}

public class DocA
{
    public string Id { get; set; }
    public string Name { get; set; }
    public Lookup Currency { get; set; }
}

public class ViewA // Simply a flattened version of the doc
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string CurrencyName { get; set; } // View just gets the name of the currency
}

Я могу создать индекс, который позволяет клиенту запрашивать представление следующим образом:

public class A_View : AbstractIndexCreationTask<DocA, ViewA>
{
    public A_View()
    {
        Map = docs => from doc in docs
                      select new ViewA
                      {
                          Id = doc.Id,
                          Name = doc.Name,
                          CurrencyName = doc.Currency.Name
                      };

        Reduce = results => from result in results
                      group on new ViewA
                      {
                          Id = result.Id,
                          Name = result.Name,
                          CurrencyName = result.CurrencyName
                      } into g
                      select new ViewA
                      {
                          Id = g.Key.Id,
                          Name = g.Key.Name,
                          CurrencyName = g.Key.CurrencyName
                      };
    }
}

Это, безусловно, работает и дает желаемый результатпредставление с данными, преобразованными в структуру, требуемую в клиентском приложении.Тем не менее, это неоправданно многословно, будет кошмаром обслуживания и, вероятно, довольно неэффективно со всей избыточной конструкции объекта.

Существует ли более простой способ создания индекса с требуемой структурой (ViewA) для данной коллекции документов (DocA)?

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ Проблема заключается в том, что для того, чтобы индекс содержал данные в преобразованной структуре (ViewA), мы должны сделать Reduce.Похоже, что Reduce должен иметь как GROUP ON, так и SELECT, чтобы работать должным образом, поэтому следующее недопустимо:

НЕПРАВИЛЬНОЕ СНИЖЕНИЕ КЛАУЗ 1:

        Reduce = results => from result in results
                      group on new ViewA
                      {
                          Id = result.Id,
                          Name = result.Name,
                          CurrencyName = result.CurrencyName
                      } into g
                      select g.Key;

Это приводит к: System.InvalidOperationException: инициализатор переменной select должен иметь лямбда-выражение с выражением создания объекта

Ясно, что нам нужно иметь 'select new'.

INVALIDУМЕНЬШЕНИЕ ОБЪЕКТА 2:

        Reduce = results => from result in results
                      select new ViewA
                      {
                          Id = result.Id,
                          Name = result.Name,
                          CurrencyName = result.CurrencyName
                      };

Это приводит к: System.InvalidCastException: Невозможно привести объект типа 'ICSharpCode.NRefactory.Ast.IdentifierExpression' к типу ICSharpCode.NRefactory.Ast.InvocationExpression.

Понятно, что нам также нужно иметь «группу новых».

Спасибо за любую помощь, которую вы можете предоставить.

(Примечание: удаление типа (ViewA) извызовы конструктора не влияют на вышесказанное)

ОБНОВЛЕНИЕ С ПРАВИЛЬНЫМ ПОДХОДОМ

Как указано в блоге Дэниела, упомянутом в ответе ниже, вот правильный способ сделатьэто для этого примера:

public class A_View : AbstractIndexCreationTask<DocA, ViewA>
{
    public A_View()
    {
        Map = docs => from doc in docs
                      select new ViewA
                      {
                          Id = doc.Id,
                          Name = doc.Name,
                          CurrencyName = doc.Currency.Name
                      };

        // Top-level properties on ViewA that match those on DocA
        // do not need to be stored in the index.
        Store(x => x.CurrencyName, FieldStorage.Yes);
    }
}

1 Ответ

4 голосов
/ 02 ноября 2012

Одно решение, просто свести на карту и настроить индекс для хранения только свойств, которые не существуют в DocA.

public class A_View : AbstractIndexCreationTask<DocA, ViewA>
{
    public A_View()
    {
        Map = docs => from doc in docs
                      select new ViewA
                      {
                          Id = doc.Id,
                          Name = doc.Name,
                          CurrencyName = doc.Currency.Name
                      };

        // Top-level properties on ViewA that match those on DocA
        // do not need to be stored in the index.
        Store(x => x.CurrencyName, FieldStorage.Yes);
    }
}
...