2015-04-26 123 views
0

需要RavenDB的幫助。RavenDB多對多和索引

在我的網頁我想有這樣的名單:

  • 物品1組別
  • ITEM2產品組別
  • ...

和另一個問題:

  • 類別1,項目數量
  • 產品組別,項目
  • 數...

我的數據結構:

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

指數第一個列表:

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

這是數據結構適合我case,還是最好在項目結構中有Category而不是CategoryId

我應該使用我的索引還是有更好的解決方案來取類別名稱?

如果我的索引很好,如何編寫正確的查詢?我目前的嘗試:

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

但它引發異常,說明返回類型是項目,而不是結果。如何解決它?

+0

你能解釋爲什麼你需要兩個列表嗎? –

回答

1

這裏有幾個選項。您可以在Item實體上存儲CategoryId和CategoryName。這當然會導致重複的數據(如果您仍然需要存儲類別實體),但「存儲便宜」是近來流行的術語。缺點是您需要更新給定類別的每個Item文檔如果類別名稱更改以保持一致。一個好處是你需要做更少的工作來獲得你想要的結果。

如果您還在商品上存儲商品類別名稱,那麼您不需要特殊的索引來處理第一個商品列表,只需查詢商品並返回您所需的商品。對於第二個列表,您需要在分類上的Item實體上創建Map/Reduce索引。

但是,如果您需要使用您提供的數據結構,有幾種解決方法。首先,真的不建議在索引定義中使用LoadDocument,尤其不要在select語句中使用LoadDocument。這可能會對索引性能產生負面影響。

相反,只指數還需要在查詢(或使用自動索引),然後使用一個結果變壓器從相關文件中讀取信息的屬性:

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

您可以使用該變壓器具有查詢對項目實體:

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

至於第二個列表,仍然使用你的數據結構,你必須使用一些東西。首先,一個Map/Reduce的價格指數比項目,按類別編號分組:

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

但是當你只擁有的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; } 
} 

最後,查詢這樣的:

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

正如你所看到的,有這取決於你使用的是什麼數據結構,做工相當的差別需要。如果您直接在項目實體上存儲了類別名稱,則不需要任何結果轉換器就可以實現您之後的結果(您只需要一個Map/Reduce索引)。

但是,結果變換器在服務器端執行,並且只在請求時執行,而不是在每次索引發生時執行的索引內部使用LoadDocument。另外,也可能是爲什麼不建議在索引定義中使用LoadDocuments,因此索引中LoadDocument引用的文檔的每次更改都會導致該索引必須重寫。這可能會導致索引引擎的很多工作。

最後,回答最後一個問題:爲什麼在查詢時出現異常:由於索引的實際返回類型是索引的文檔(在本例中爲Item)。要使用別的東西,你需要將你的結果投影到別的東西上。這可以通過在查詢中使用「.As()」來完成:

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

很長的帖子,但希望它有幫助!

+0

哇,很好的解釋!非常感謝。 – limpo