これがあなたの質問に答えるのに十分かどうかはわかりませんが、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
. この値は頻繁に変更されることはありませんが、変更される可能性があるため、クラスに保持されているプロパティのUserName
プロパティを更新する方法が必要です。変更を行うには、まずRavenDB から正しいインスタンスを見つける必要があり、そのためにはインデックスが必要です。UserReference
Assessment
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
ユーザー関連のすべての機能を調整するのに役立つクラスがあるので、そこにこのコードを配置します。
このコードを他の参照用に再利用するため、少し抽象化されています。これは、必要なより複雑な階層 (またはおそらく「ドメイン グラフ」の方が適切な説明) を作成するのに役立ちます。
ユーザーサービス
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
}
}
}
};
}
それだ。そして、あなたが知っているように、私はそれをすべてレイアウトしたので、あなたが何を意味するかがわかります。リファレンスを更新するだけでも大変な作業です。おそらく、Service コードをより DRY にして、さまざまな関係タイプに再利用できますが、参照されるタイプごとに 1 つずつ、多数のインデックスを作成することから逃れる方法がわかりません。