2012-03-27 9 views
5

Dadas las siguientes clases:forma más sencilla de aplanar documento en una vista en RavenDB

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 
} 

que puedo crear un índice que permite cliente para consultar la vista de la siguiente manera:

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

Esto ciertamente funciona y produce el resultado deseado de una vista con los datos transformados a la estructura requerida en la aplicación del cliente. Sin embargo, es muy prolijo, será una pesadilla de mantenimiento y probablemente sea bastante ineficiente con toda la construcción de objetos redundantes.

¿Existe una manera más simple de crear un índice con la estructura requerida (ViewA) dada una colección de documentos (DocA)?

MÁS INFORMACIÓN El problema parece ser que con el fin de tener el índice de contener los datos en la estructura transformada (viewa), tenemos que hacer un Reducir. Parece que una Reducir debe tener tanto un grupo ON y un SELECT con el fin de funcionar como se espera por lo que la siguientes no son válidos:

VÁLIDA REDUCIR Cláusula 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; 

Esto produce: Sistema. InvalidOperationException: la selección del inicializador de variables debe tener una expresión lambda con un objeto create expression

Claramente necesitamos tener 'seleccionar nuevo'.

NO VÁLIDA REDUCIR Cláusula 2:

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

Este prduces: System.InvalidCastException: No se puede convertir objeto de tipo 'ICSharpCode.NRefactory.Ast.IdentifierExpression' al tipo 'ICSharpCode.NRefactory.Ast.InvocationExpression '.

Claramente, también necesitamos tener el 'grupo en nuevo'.

Gracias por cualquier ayuda que pueda proporcionar.

(Nota: la eliminación del tipo (viewa) de las llamadas a constructores no tiene ningún efecto en lo anterior)

ACTUALIZACIÓN CON CORRECTO ENFOQUE

Como se indica en el blog de Daniel se menciona en la respuesta a continuación, aquí es la forma correcta de hacer esto para este ejemplo:

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); 
    } 
} 
+0

Gracias @Phill. No sé qué pasó con otra respuesta que estaba aquí ... –

Respuesta

4

Una solución, simplemente aplanar en el mapa y configurar el índice para almacenar únicamente las propiedades que no existen en la 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); 
    } 
} 
+0

Solo una nota de algo que estuve cuidando por un tiempo; Si desea utilizar el índice para consultar y obtener la entidad original que está consultando, puede hacerlo: 'DocumentSession.Query (). Where (x => x.CurrencyName == "EUR").Como () .Primer(); ' [Encontrado aquí] (http://ayende.com/blog/152833/orders-search-in-ravendb) –

Cuestiones relacionadas