我想在存储在RavenDB文档数据库中的两个实体之间有一个引用.由于这不是关系数据库,我知道我应该使用RavenDBs文档中描述的非规范化引用技术.虽然起初这看起来很好,但是一旦我开始创建包含双向引用的真实世界域"层次结构",保持所有这些引用最新的努力感觉不成比例.我觉得我可能在某个地方出错了.
你能解释使用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; }
}
Run Code Online (Sandbox Code Playgroud)
你可以看到我有一个Assessment引用a 的类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
};
}
}
Run Code Online (Sandbox Code Playgroud)
注意引用类如何也带有UserName.此值不会经常更改,但可能会更改,因此我们需要一种方法来更新类中保留的UserName属性中的UserReference属性Assessment.要进行更改,我们必须首先Assessment从RavenDB中找到正确的实例,为此我们需要一个索引.
乌鸦指数
public class Assessment_ByUserId : AbstractIndexCreationTask<Assessment>
{
public Assessment_ByUserId()
{
Map = assessments => from assessment in assessments
select new
{
User_Id = assessment.User.Id
};
}
}
Run Code Online (Sandbox Code Playgroud)
该指数需要每当被调用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
}
}
}
};
}
Run Code Online (Sandbox Code Playgroud)
这就对了.你知道,现在我全力以赴,我可以看出你的意思.这是大量的工作只是为了更新的参考.也许服务代码可以更加干燥并重用于不同的关系类型,但我没有看到如何摆脱编写大量索引,每个引用类型一个.