Ravendb 转化结果

Ravendb 转化结果,ravendb,indexing,Ravendb,Indexing,我的同事问我,如果给出示例,是否可以初始化如下所示的viewmodel: OrderViewModel string OrderId string CustomerName List<OrderLineViewModel> OrderLines OrderLineViewModel string ProductName string ROI int Quantity public class Order { public string

我的同事问我,如果给出示例,是否可以初始化如下所示的viewmodel:

OrderViewModel
   string OrderId
   string CustomerName
   List<OrderLineViewModel> OrderLines

OrderLineViewModel
   string ProductName
   string ROI
   int Quantity
public class Order
{
    public string Id { get; set; }
    public string CustomerId { get; set; }
    public List<OrderLine> OrderLines { get; set; }
}

public class OrderLine
{
    public string ProductId { get; set; }
    public int Quantity { get; set; }
}

public class Customer
{
    public string Id { get; set; }
    public string Name { get; set; }
}

public class Product
{
    public string Id { get; set; }
    public string Name { get; set; }
}
var results = session.Query<Order>().Where(x => x.CustomerId == theCustomerId);
orderview模型
字符串医嘱ID
字符串客户名称
列出订单行
OrderLineViewModel
字符串产品名称
字符串ROI
整数
从一个索引

我曾尝试过成功加载客户名称的转换,但始终无法从订单行获取相关的产品信息。这可以通过转换完成,还是需要从索引字段进行投影

干杯

詹姆斯

编辑:

我们试图直接从查询填充视图模型。 我们尝试了以下索引:

public class OrdersViewIndex : AbstractIndexCreationTask<Order>
{
   Map = orders => from order in orders
                   select new {
                                OrderId = order.id
                              };

   Transform = (database, orders) => from order in orders
                                     let customer = database.Load<Customer>(order.customerId)
                                     select new {
                                                  OrderId = order.id,
                                                  CustomerName = customer.Name,
                                                  OrderLines = // This is where I struggled to answer my colleagues questions as i'd need to load product name.
                                                }
}
公共类OrdersViewIndex:AbstractIndexCreationTask
{
Map=orders=>来自订单中的订单
选择新的{
OrderId=order.id
};
转换=(数据库,订单)=>来自订单中的订单
让customer=database.Load(order.customerId)
选择新的{
OrderId=order.id,
CustomerName=customer.Name,
OrderLines=//这是我努力回答同事问题的地方,因为我需要加载产品名称。
}
}

首先,认识到所有索引都会自动将
Id
映射到名为
\u document\u Id
的索引项中。因此,再次映射它并没有多大价值。您在这个索引映射中所做的只是将它再次复制到另一个名为
OrderId
的索引项中

其次,要理解转换实际上不是索引的一部分,而只是附加到索引定义并在运行时执行。它们真正提供的只是一种在服务器上变形查询结果的方法。在大多数情况下,这些都是您可以在客户端完成的事情

第三,索引用于查询非id字段,并提供but结果。当您通过文档的
Id
(也称为文档键)检索文档时,使用索引是毫无意义的。您希望改用
.Load()
方法,该方法提供了保证,并且只从数据库检索文档

现在-您遇到了一个问题,即当您的文档只有客户id时,如何获取客户名称,以及如何获取产品名称而不仅仅是产品id。假设您的文档如下所示:

OrderViewModel
   string OrderId
   string CustomerName
   List<OrderLineViewModel> OrderLines

OrderLineViewModel
   string ProductName
   string ROI
   int Quantity
public class Order
{
    public string Id { get; set; }
    public string CustomerId { get; set; }
    public List<OrderLine> OrderLines { get; set; }
}

public class OrderLine
{
    public string ProductId { get; set; }
    public int Quantity { get; set; }
}

public class Customer
{
    public string Id { get; set; }
    public string Name { get; set; }
}

public class Product
{
    public string Id { get; set; }
    public string Name { get; set; }
}
var results = session.Query<Order>().Where(x => x.CustomerId == theCustomerId);
如果要将这些项目投影到视图模型,如之前一样,可以使用包括:

var results = session.Query<Order>()
    .Customize(x => x.Include<Order>(y => y.CustomerId)
                     .Include<Order>(y => y.OrderLines.Select(z => z.ProductId)))
    .Where(x => x.CustomerId == theCustomerId)
    .Select(x => new OrderVM
    {
        OrderId = x.Id,
        CustomerId = x.CustomerId,
        CustomerName = session.Load<Customer>(x.CustomerId).Name,
        OrderLines = order.OrderLines.Select(y => new OrderLineVM
        {
            ProductId = y.ProductId,
            ProductName = session.Load<Product>(y.ProductId).Name,
            Quantity = y.Quantity
        })
    });
如果愿意,可以将其与include或Transform技术相结合,以获取完整视图模型

另一种技术是存储这些字段和。这对于单个字段(如
CustomerName
)非常有效,但对于复杂值(如
OrderLines
)可能过于苛刻

最后,另一个需要考虑的技术是。考虑一下,<>代码>产品<代码>可能会更改它的名称,或者被删除。您可能不想使以前的订单无效。最好将与订单相关的任何产品数据复制到
OrderLine
对象中

public class OrderLine
{
    public string ProductId { get; set; }
    public string ProductName { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
}
一旦您这样做了,您就不再需要在检索订单时加载产品数据。变换部分变得不必要,只剩下一个简单的索引投影,如下所示:

public class Orders_Transformed : AbstractIndexCreationTask<Order>
{
    public Orders_Transformed()
    {
        Map = orders => from order in orders select new { };

        TransformResults = (database, orders) =>
            from order in orders
            select new
            {
                OrderID = order.Id,
                CustomerID = order.CustomerId,
                CustomerName = database.Load<Customer>(order.CustomerId).Name,
                OrderLines = order.OrderLines.Select(y => new
                    {
                        ProductId = y.ProductId,
                        ProductName = database.Load<Product>(y.ProductId).Name,
                        Quantity = y.Quantity
                    })
            };
    }
}
Map = orders => from order in orders
                select new
                {
                    CustomerName = LoadDocument<Customer>(order.CustomerId)
                };
public class Orders_ByCustomerName : AbstractIndexCreationTask<Order>
{
    public Orders_ByCustomerName()
    {
        Map = orders => from order in orders
                        select new
                        {
                          CustomerName = LoadDocument<Customer>(order.CustomerId).Name
                        };

        Store("CustomerName", FieldStorage.Yes);
    }
}
公共类订单\u按客户名称:AbstractIndexCreationTask
{
公共秩序由客户名称()
{
Map=orders=>来自订单中的订单
选择新的
{
CustomerName=LoadDocument(order.CustomerId).Name
};
商店(“客户名称”,FieldStorage.Yes);
}
}
您可以使用以下工具轻松查询:

var results = session.Query<OrderVM, Orders_ByCustomerName>()
                     .Where(x => x.CustomerName == "Joe")
                     .As<OrderVM>();
var results=session.Query()
.Where(x=>x.CustomerName==“Joe”)
.As();
注意,在查询中,我第一次指定
OrderVM
,是在定义索引项的形状。它只是设置lambda,以便我可以指定
x.CustomerName==“Joe”
。通常,您会看到用于此目的的特殊“结果”类。这真的没关系——我可以使用任何具有
CustomerName
string字段的类

当我指定
.As()
-这就是我实际从
订单
类型移动到
订单虚拟机
类型的地方-并且
客户名称
字段在我们为它打开字段存储后就出现了

TL;DR


RavenDB有很多选择。尝试找出适合你需要的东西。正确的文档设计,以及小心地使用with
LoadDocument()
通常会消除索引转换的需要。

在大多数情况下,您不需要转换,只需在自己的代码中进行转换即可。请把你试过的东西贴出来。非常感谢你花了这么多时间在马特身上,因为你的答案总是很有帮助的。。这一个超过了他们所有人我和同事们一直在努力找出该做什么/不该做什么以及什么时候/为什么-我会让每个人都读这个答案再次感谢!在Ravendb2.5中,现在有了的概念。我将很快更新此答案,以解释它们。
var results = session.Query<OrderVM, Orders_ByCustomerName>()
                     .Where(x => x.CustomerName == "Joe")
                     .As<OrderVM>();