我想在存儲在RavenDB文檔數據庫中的兩個實體之間有一個引用。由於這不是關係數據庫,我知道我應該使用RavenDBs文檔中描述的非規範化引用技術。雖然起初這看起來很好,但一旦我開始創建包含雙向引用的真實世界域「層次結構」,保持所有這些引用爲最新的努力會感覺不成比例。我覺得我可能會在某個地方出錯。如何在RavenDB中實現非規範化引用
你能解釋一下使用RavenDB建模一個相當複雜的域結構的最好/最簡單的方法嗎?
感謝
我想在存儲在RavenDB文檔數據庫中的兩個實體之間有一個引用。由於這不是關係數據庫,我知道我應該使用RavenDBs文檔中描述的非規範化引用技術。雖然起初這看起來很好,但一旦我開始創建包含雙向引用的真實世界域「層次結構」,保持所有這些引用爲最新的努力會感覺不成比例。我覺得我可能會在某個地方出錯。如何在RavenDB中實現非規範化引用
你能解釋一下使用RavenDB建模一個相當複雜的域結構的最好/最簡單的方法嗎?
感謝
我不知道這是否會遠遠不夠回答你的問題,但這裏是我如何去創造RavenDB一個非標準化的參考(這是從真正的代碼取爲清楚起見移除非必需品)
域
public class User : IUserIdentity
{
public string UserName { get; set; }
public IEnumerable<string> Claims { get; set; }
public string Id { get; set; }
public Guid FormsAuthenticationGuid { get; set; }
}
public class Assessment
{
public string Id { get; set; }
public UserReference User { get; set; }
public AssessmentState State { get; set; }
}
你可以看到,我有一個Assessment
類引用User
。此用戶參考使用下面的UserReference
類進行管理。
規格化參考
public class UserReference
{
public string Id { get; set; }
public string UserName { get; set; }
public static implicit operator UserReference(User user)
{
return new UserReference
{
Id = user.Id,
UserName = user.UserName
};
}
}
注意如何引用類也攜帶UserName
。此值不會經常更改,但可能會更改,因此我們需要更新Assessment
類中保存的UserReference
屬性中UserName
屬性的方法。要做出改變,我們必須首先從RavenDB中找到正確的Assessment
實例,爲此我們需要一個索引。
烏鴉指數
public class Assessment_ByUserId : AbstractIndexCreationTask<Assessment>
{
public Assessment_ByUserId()
{
Map = assessments => from assessment in assessments
select new
{
User_Id = assessment.User.Id
};
}
}
該指數需要每當User
的UserName
值更新爲被調用。我有一個UserService
類,它可以幫助我協調所有與用戶有關的功能,所以這就是我放置這些代碼的地方。
我重複使用此代碼的其他參考,所以它已被抽象出一點。這可以幫助您創建更復雜的層次結構(或者「域圖」更好地描述)。
UserService
public static void SetUserName(IDocumentSession db, string userId, string userName)
{
var user = db.Load<User>(userId);
user.UserName = userName;
db.Save(user);
UpdateDenormalizedReferences(db, user, userName);
}
private static void UpdateDenormalizedReferences(IDocumentSession db, User user, string userName)
{
db.Advanced.DatabaseCommands.UpdateByIndex(
RavenIndexes.IndexAssessmentByUserId,
GetQuery(user.Id),
GetUserNamePatch(userName),
allowStale: true);
}
private static IndexQuery GetQuery(string propertyValue, string propertyName = "User_Id")
{
return new IndexQuery {Query = string.Format("{0}:{1}", propertyName, propertyValue)};
}
private static PatchRequest[] GetUserNamePatch(string referenceValue, string referenceName = "User")
{
return new[]
{
new PatchRequest
{
Type = PatchCommandType.Modify,
Name = referenceName,
Nested = new[]
{
new PatchRequest
{
Type = PatchCommandType.Set,
Name = "UserName",
Value = referenceValue
}
}
}
};
}
這就是它。而且你知道,現在我全力以赴瞭解了你的意思。它是很多工作只是爲了更新參考。也許服務代碼可以做得更幹,並且可以重用於不同的關係類型,但是我不知道如何避免編寫大量的索引,每個引用類型一個索引。
非常感謝生物分形,我嘗試了更復雜的路線,這看起來很理想。 –
此博客文章可能會幫助您決定:http://daniellang.net/how-to-handle-relations-in-ravendb/ – dasheddot
謝謝dasheddot,這真的很有用,謝謝。 –
這看起來很有趣。 Multi Maps/Reduce索引[here](http:// ayende。com/blog/89089/ravendb-multi-maps-reduce-indexes) – biofractal