我认为我的场景是任何应用程序中的常见场景。我将举例说明使用常用的域名:产品和订单(含产品)。
我想要做的是按产品名称搜索订单,因为订单上有一个itens列表,每个项目都有一个相关的productId。
我做了一些搜索并阅读了Raven文档,但我无法找到问题的答案。
请考虑以下代码:
public class Product
{
public string Id { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
}
public class Order
{
public string Id { get; set; }
public string OrderNumber { get; set; }
public decimal Total { get; set; }
public string Customer { get; set; }
public Item[] Items { get; set; }
}
public class Item
{
public string ProductId { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
public class Order_ByProductName : AbstractMultiMapIndexCreationTask<Order_ByProductName.Result>
{
public class Result
{
public string ProductId { get; set; }
public string ProductName { get; set; }
public string[] OrdersIds { get; set; }
public string[] OrdersNumbers { get; set; }
}
public Order_ByProductName()
{
AddMap<Product>(products => from product in products
select new
{
ProductId = product.Id,
ProductName = product.ProductName,
OrderId = default(string),
OrderNumber = default(string)
});
AddMap<Order>(orders => from order in orders
group order by order.Items.Select(c => c.ProductId)
into g
select new
{
ProductId = g.Key,
ProductName = default(string),
OrdersIds = g.Select(c => c.Id),
OrdersNumbers = g.Select(c => c.OrderNumber)
});
Reduce = results => from result in results
group result by result.ProductId
into g
select new
{
ProductId = g.Key,
ProductName = g.Select(r => r.ProductName).Where(t => t != null).First(),
OrdersIds = g.Where(r => r.OrdersIds != null).SelectMany(r => r.OrdersIds),
OrdersNumbers = g.Where(r => r.OrdersNumbers != null).SelectMany(r => r.OrdersNumbers)
};
Sort("ProductName", SortOptions.String);
Index(x => x.ProductName, FieldIndexing.Analyzed);
}
}
class Program
{
static void Main(string[] args)
{
var documentStore = new DocumentStore
{
Url = "http://localhost:8080",
DefaultDatabase = "MyDatabase"
};
documentStore.Initialize();
new Order_ByProductName().Execute(documentStore);
using (var session = documentStore.OpenSession())
{
var product1 = new Product() { Price = 100, ProductName = "Phone" };
var product2 = new Product() { Price = 1000, ProductName = "Laptop" };
var product3 = new Product() { Price = 200, ProductName = "Windows Phone" };
session.Store(product1);
session.Store(product2);
session.Store(product3);
session.SaveChanges();
}
using (var session = documentStore.OpenSession())
{
var products = session.Query<Product>().ToList();
var order1 = new Order();
order1.Customer = "Jhon Doe";
order1.OrderNumber = "001";
order1.Items = new Item[] {
new Item { ProductId = products[0].Id, Price = products[0].Price, Quantity = 1 },
new Item { ProductId = products[1].Id, Price = products[1].Price, Quantity = 1 }
};
order1.Total = order1.Items.Sum(c => (c.Quantity * c.Price));
var order2 = new Order();
order2.Customer = "Joan Doe";
order2.OrderNumber = "002";
order2.Items = new Item[] {
new Item { ProductId = products[2].Id, Price = products[2].Price, Quantity = 1 }
};
order2.Total = order2.Items.Sum(c => (c.Quantity * c.Price));
session.Store(order1);
session.Store(order2);
session.SaveChanges();
}
using (var session = documentStore.OpenSession())
{
var results = session
.Query<Order_ByProductName.Result, Order_ByProductName>()
.Where(x => x.ProductName == "Phone")
.ToList();
foreach (var item in results)
{
Console.WriteLine($"{item.ProductName}\t{string.Join(", ", item.OrdersNumbers)}");
}
Console.ReadKey();
}
}
}
我在How to index related documents in reverse direction in Ravendb找到了相关问题,但这种情况有点不同。如果您对索引创建进行注释,则会运行上面的代码,否则会抛出异常:&#34;无法理解查询:变量初始值设定项必须是选择查询表达式&#34;。
我需要像SQL下面的东西,但是在RavenDb中:
select pro.ProductName, ord.OrderNumber from orders ord
inner join items itm on itm.OrderId = ord.Id
inner join products pro on pro.Id = itm.ProductId
where pro.ProductName like '%Phone%';
如何通过ProductName创建搜索并返回RavenDb中的列表或订单? 我使用版本3.5(.1)
将主要问题视为搜索&#34;实体按相关实体属性&#34;。
提前致谢!
答案 0 :(得分:2)
考虑将产品名称直接存储在订单商品中。这将有两个好处 - 订单商品不会受到后期产品变更的影响,索引也会更便宜。
以下代码演示了两种方法:
public class Product
{
public string Id { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
}
public class Order
{
public string Id { get; set; }
public string OrderNumber { get; set; }
public decimal Total { get; set; }
public string Customer { get; set; }
public Item[] Items { get; set; }
}
public class Item
{
public string ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
public class OrderView
{
public string OrderId { get; set; }
public string OrderNumber { get; set; }
public string[] ProductIds { get; set; }
public string[] ProductNames { get; set; }
}
public class Order_ByItemName : AbstractIndexCreationTask<Order, OrderView>
{
public Order_ByItemName()
{
Map = orders => from order in orders
select new
{
OrderId = order.Id,
OrderNumber = order.OrderNumber,
ProductIds = order.Items.Select(x => x.ProductId).ToArray(),
ProductNames = order.Items.Select(x => x.ProductName).ToArray(),
};
Index(x => x.ProductNames, FieldIndexing.Analyzed);
StoreAllFields(FieldStorage.Yes);
}
}
public class Order_ByProductName : AbstractIndexCreationTask<Order, OrderView>
{
public Order_ByProductName()
{
Map = orders => from order in orders
let products = LoadDocument<Product>(order.Items.Select(x => x.ProductId))
select new
{
OrderId = order.Id,
OrderNumber = order.OrderNumber,
ProductIds = products.Select(x => x.Id).ToArray(),
ProductNames = products.Select(x => x.ProductName).ToArray(),
};
Index(x => x.ProductNames, FieldIndexing.Analyzed);
StoreAllFields(FieldStorage.Yes);
}
}
class Program
{
static void Main(string[] args)
{
var documentStore = new DocumentStore
{
Url = "http://localhost:8080",
DefaultDatabase = "MyDatabase"
};
documentStore.Initialize();
new Order_ByProductName().Execute(documentStore);
new Order_ByItemName().Execute(documentStore);
using (var session = documentStore.OpenSession())
{
var product1 = new Product() { Id = "products/1", Price = 100, ProductName = "Phone" };
var product2 = new Product() { Id = "products/2", Price = 1000, ProductName = "Laptop" };
var product3 = new Product() { Id = "products/3", Price = 200, ProductName = "Windows Phone" };
session.Store(product1);
session.Store(product2);
session.Store(product3);
session.SaveChanges();
}
using (var session = documentStore.OpenSession())
{
var products = session.Query<Product>().ToList();
var order1 = new Order();
order1.Id = "orders/1";
order1.Customer = "Jhon Doe";
order1.OrderNumber = "001";
order1.Items = new Item[] {
new Item { ProductId = products[0].Id, ProductName = products[0].ProductName, Price = products[0].Price, Quantity = 1 },
new Item { ProductId = products[1].Id, ProductName = products[1].ProductName, Price = products[1].Price, Quantity = 1 }
};
order1.Total = order1.Items.Sum(c => (c.Quantity * c.Price));
var order2 = new Order();
order1.Id = "orders/1";
order2.Customer = "Joan Doe";
order2.OrderNumber = "002";
order2.Items = new Item[] {
new Item { ProductId = products[2].Id, ProductName = products[2].ProductName, Price = products[2].Price, Quantity = 1 }
};
order2.Total = order2.Items.Sum(c => (c.Quantity * c.Price));
session.Store(order1);
session.Store(order2);
session.SaveChanges();
}
Thread.Sleep(5000); // wait for indexing
using (var session = documentStore.OpenSession())
{
var itemResults = session
.Query<OrderView, Order_ByItemName>()
.Search(x => x.ProductNames, "Phone")
.ProjectFromIndexFieldsInto<OrderView>()
.ToList();
var results = session
.Query<OrderView, Order_ByProductName>()
.Search(x => x.ProductNames, "Phone")
.ProjectFromIndexFieldsInto<OrderView>()
.ToList();
Console.WriteLine("Order_ByItemName");
foreach (var order in itemResults)
{
Console.WriteLine($"OrderNumber: {order.OrderNumber}");
for (int i = 0; i < order.ProductIds.Length; i++)
{
Console.WriteLine($"Item: {order.ProductIds[i]} - {order.ProductNames[i]}");
}
}
Console.WriteLine("Order_ByProductName");
foreach (var order in results)
{
Console.WriteLine($"OrderNumber: {order.OrderNumber}");
for (int i = 0; i < order.ProductIds.Length; i++)
{
Console.WriteLine($"Item: {order.ProductIds[i]} - {order.ProductNames[i]}");
}
}
Console.ReadKey();
}
}
}