2013-07-01 37 views
1

我在這個班的RavenDB集合...查詢過在RavenDB組合鍵集合使用C#

public class Report 
{ 
    public string User { get; set; } 
    public int Quarter { get; set; } 
    public int Year { get; set; } 
    public string ReportData { get; set; } 
} 

有每季度只有一個報告,每年爲每個用戶(所以識別。關鍵是{ User, Quarter, Year }我想創建一個函數來保存這些報告的列表,覆蓋舊文件或插入新的需要,我想出了這一點:

public void Save(IList<Report> reports) 
{ 
    session.Query<Report>() 
     .Join(reports, 
      x => new { x.User, x.Quarter, x.Year }, 
      y => new { y.User, y.Quarter, y.Year }, 
      (x, y) => new { OldReport = x, NewReport = y }) 
     .ForEach(report => 
     { 
      if (report.OldReport != null) 
       report.OldReport.InjectFrom(report.NewReport); 
      else 
       session.Store(report.NewReport); 
     }); 

    session.SaveChanges(); 
} 

然而,RavenDB不支持.Join操作編輯:我是意識到這也需要成爲一個正確的外部連接才能發揮作用,但我認爲它表達了我的意圖。我知道我需要做某種Map Reduce來實現這一點,但我是RavenDB的新手,我找不到與我正在做的事情相關的任何好例子。有沒有人嘗試過這樣的事情?

P.S.如果有人想知道,.InjectFrom()操作正在使用Omu.ValueInjecter

回答

3

有多種方法可以做到這一點,但最簡單的方法是提供自己的文檔密鑰,而不是使用Raven生成的文件密鑰。這通常被稱爲使用「結構化」或「語義」鍵。 Here is a good description of the general technique

只需將字符串Id屬性添加到您的班級。您希望文檔關鍵字反映您描述的唯一關鍵字,因此可能它應該有一個值,如"reports/2013/Q1/bob"(但您可能需要爲user設置更爲獨特的值)。

你可以讓淨構建關鍵你的屬性的getter,如:

public class Report 
{ 
    public string Id 
    { 
     get { return string.Format("reports/{0}/Q{1}/{2}", Year, Quarter, User); } 
    } 

    public string User { get; set; } 
    public int Quarter { get; set; } 
    public int Year { get; set; } 
    public string ReportData { get; set; } 
} 

現在,當你保存這些文件,只需存儲這些:

foreach (var report in reports) 
    session.Store(report); 

如果有已經是具有相同密鑰的文檔,它將被您的新數據覆蓋。否則,將寫入一個新文檔。

如果你不能操縱文檔鍵,你可以看看其他的技術有:

  • 你可以運行一個查詢,刪除第一個匹配的改變數據的任何文件。然後你可以插入所有的數據。但是,由於有多個字段可以匹配,因此獲取正確的查詢將很困難。這是可能的,但技術是具有挑戰性的。

  • 您可以使用Patching API來操作已存儲文檔的數據。儘管您仍然需要查詢以確定哪些是新插入,哪些是更新。此外,補丁將不得不針對整個數據庫進行測試,因此速度會很慢。

我敢肯定還有其他一些想法,但最安全和最簡單的賭注是使用語義鍵爲報告。