简体   繁体   English

RavenDB多对多索引

[英]RavenDB many to many and indexes

Need a help with RavenDB. 需要有关RavenDB的帮助。

In my web page I want to have such list: 在我的网页上,我想要这样的列表:

  • item1 category1 item1类别1
  • item2 category2 item2 category2
  • ... ...

and another one: 还有一个:

  • category1, number of items category1,项目数
  • category2, number of items category2,项目数
  • ... ...

My data structures: 我的数据结构:

public class Item
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string CategoryId { get; set; }
}


public class Category
{
    public string Id { get; set; }
    public string Name { get; set; }
    public bool IsActive { get; set; }
}

Index for the first list: 第一个列表的索引:

public class Item_WithCategory : AbstractIndexCreationTask<Item>
{
    public class Result
    {
        public string Name { get; set; }
        public string CategoryName { get; set; }
    }

    public Item_WithCategory()
    {
        Map = items => from item in items
              select new
                  {
                      Name = item.Name,
                      CategoryName = LoadDocument<Category>(item.CategoryId).Name
                  };
    }
}

Is this data structure suitable for my case, or will it be better to have Category instead of CategoryId in item structure? 此数据结构是否适合我的情况,还是在项目结构中使用Category而不是CategoryId更好?

Should I use my index or is there a better solution to take category name? 我应该使用索引还是有更好的解决方案来获取类别名称?

If my index is good, how to write a correct query? 如果我的索引很好,如何编写正确的查询? My current try: 我目前的尝试:

    Item_WithCategory.Result[] all;
    using (var session = DocumentStoreHolder.Store.OpenSession())
    {
        all = session.Query<Item_WithCategory.Result, Item_WithCategory>().ToArray();
    }

but it throws exception stating that return type is item, not result. 但是它抛出异常,指出返回类型是项,而不是结果。 How to fix it? 如何解决?

You have a couple of options here. 您在这里有几个选择。 You could store both the CategoryId and the CategoryName on the Item entity. 您可以将CategoryId和CategoryName都存储在Item实体上。 This will of course lead to duplicated data (if you still need to store the Category entity), but "storage is cheap" is a popular term these days.The downside of this is that you need to update each Item document of a given category if the category name changes to keep things consistent. 当然,这将导致数据重复(如果您仍然需要存储Category实体),但是“存储便宜”是当今流行的术语。它的缺点是您需要更新给定类别的每个Item文档如果类别名称更改以保持一致。 A benefit is that you need to do less work to get your desired result. 这样做的好处是,您只需要做较少的工作即可获得所需的结果。

If you store Category Name on the item as well you don't need a special index to handle the first list, just query on the Items and return what you need. 如果您也将类别名称存储在项目上,则不需要特殊索引来处理第一个列表,只需在项目上查询并返回所需内容即可。 For the second list you need to create a Map/Reduce index on the Item entity that groups on the category. 对于第二个列表,您需要在对类别进行分组的Item实体上创建Map / Reduce索引。

However, if you need to use the data structure you've given, there are a couple of ways of solving this. 但是,如果您需要使用给定的数据结构,则有两种解决方法。 First, it's really not recommended to use a LoadDocument inside of an index definition, especially not in a select statement. 首先,实际上不建议在索引定义内使用LoadDocument,尤其是不要在select语句中使用。 This might affect indexing performance in a negative way. 这可能会对索引性能产生负面影响。

Instead, just index the properties you need to query on (or use an auto index) and then use a Result Transformer to fetch information from related documents: 相反,只需对需要查询的属性建立索引(或使用自动索引),然后使用结果转换器从相关文档中获取信息:

public class ItemCategoryTransformer : AbstractTransformerCreationTask<Item>
{
    public ItemCategoryTransformer()
    {
        TransformResults = results => from item in results
                                      let category = LoadDocument<Category>(item.CategoryId)
                                      select new ItemCategoryViewModel
                                      {
                                          Name = item.Name,
                                          CategoryName = category.Name
                                      };
    }
}

public class ItemCategoryViewModel
{
    public string Name { get; set; }
    public string CategoryName { get; set; }
}

You can use this Transformer with a Query on the Item entity: 您可以将此Transformer与Item实体上的查询一起使用:

using (var session = documentStore.OpenSession())
{
    var items = session.Query<Item>()
                        .TransformWith<ItemCategoryTransformer, ItemCategoryViewModel>()
                        .ToList();
}

As for the second list, still using your data structure, you have to use a couple of things. 至于第二个列表,仍然使用您的数据结构,您必须使用一些方法。 First, a Map/Reduce index over the Items, grouped by CategoryId: 首先,对商品按Map / Reduce索引进行分类(按CategoryId分组):

public class Category_Items_Count : AbstractIndexCreationTask<Item, Category_Items_Count.Result>
{
    public class Result
    {
        public string CategoryId { get; set; }
        public int Count { get; set; }
    }

    public Category_Items_Count()
    {
        Map = items => from item in items

            select new Result
            {
                CategoryId = item.CategoryId,
                Count = 1
            };

        Reduce = results => from result in results
            group result by result.CategoryId
            into c
            select new Result
            {
                CategoryId = c.Key,
                Count = c.Sum(x => x.Count)
            };
    }
}

But as you only have the CategoryId on the Item entity, you have to use a similar transformer as in the first list: 但是,由于在Item实体上只有CategoryId,因此必须使用与第一个列表类似的转换器:

public class CategoryItemsCountTransformer : AbstractTransformerCreationTask<Category_Items_Count.Result>
{
    public CategoryItemsCountTransformer()
    {
        TransformResults = results => from result in results
            let category = LoadDocument<Category>(result.CategoryId)
            select new CategoryItemsCountViewModel
            {
                CategoryName = category.Name,
                NumberOfItems = result.Count
            };
    }
}

public class CategoryItemsCountViewModel
{
    public string CategoryName { get; set; }
    public int NumberOfItems { get; set; }
}

And lastly, query for it like this: 最后,像这样查询它:

using (var session = documentStore.OpenSession())
{
    var items = session.Query<Category_Items_Count.Result, Category_Items_Count>()
                       .TransformWith<CategoryItemsCountTransformer, CategoryItemsCountViewModel>()
                       .ToList();
}

As you can see, there are quite a difference in work needed depending on what data structure you're using. 如您所见,根据您使用的数据结构,工作需要有很大的不同。 If you stored the Category Name on the Item entity directly you wouldn't need any Result Transformers to achieve the results you're after (you would only need a Map/Reduce index). 如果将类别名称直接存储在Item实体上,则不需要任何结果转换器即可获得所需的结果(您只需要一个Map / Reduce索引)。

However, Result Transformers are executed server side and are only executed on request, instead of using LoadDocument inside of an index which is executed every time indexing occurs. 但是,结果转换器在服务器端执行,并且仅在请求时执行,而不是在每次发生索引时都会在索引内使用LoadDocument。 Also, and maybe why LoadDocuments inside of index definitions isn't recommended, every change to a document that's referenced with a LoadDocument in an index will cause that index to have to be rewritten. 此外,也许不建议为什么在索引定义内使用LoadDocuments,对索引中使用LoadDocument引用的文档的每次更改都会导致必须重写该索引。 This might lead to a lot of work for the index engine. 这可能会导致索引引擎的大量工作。

Lastly, to answer your last question about why you get an exception when querying: As the actual return type of your index is the document that that's being indexed (in this case Item). 最后,回答关于查询时为什么会出现异常的最后一个问题:由于索引的实际返回类型是被索引的文档(在本例中为Item)。 To use something else you need to project your result to something else. 要使用其他东西,您需要将结果投影到其他东西。 This can be done by using ".As()" in the query: 这可以通过在查询中使用“ .As()”来完成:

Item_WithCategory.Result[] all;
using (var session = DocumentStoreHolder.Store.OpenSession())
{
    all = session.Query<Item_WithCategory.Result, Item_WithCategory>()
        .As<Item_WithCategory.Result>()         
        .ToArray();
}

Long post, but hope it helps! 帖子很长,但希望对您有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM