0

私は RavenDB に永続化されたエンティティを持っています:

public class Project: RootAggregate
{        
    public string Name { get; set; }        
}

public class Profile: RootAggregate
{
    public string User { get; set; }
    public IList<Project> FavoriteProjects { get; set; }
}

これはリレーショナル データベースではなくドキュメント データベースであるため、非正規化されており、問題ないはずです。とにかく、私はこのように設計しませんでした:

public class Profile: RootAggregate
{
    public string User { get; set; }
    public IList<string> FavoriteProjectsIds { get; set; }
}

ただし、最新のプロジェクトをロードする必要がある場合があります (この場合、最新の名前で)。以下のようにを使用できるAyende ブログを読みました。Include()

var profile = session.Include<Project>(x => x.Id)
                     .Load<Profile>(Id);

まず、次の文を考えました。

var projects = profile.FavouriteProjects;

マージされた最新の結果が得られますが、いいえ。私は混乱しましたが、さらに読んで、問題ないことに気付きましたが、以下のクエリは 2 回目にデータベースに到達しないはずです (Ayende の投稿を理解している限り):

var projectsIds = profile.FavoriteProjects.Select(x => x.Id).ToList();
var projects = session.Load<Project>(projectsIds);

私は正しいですか?ブログで 1 つのエンティティ ( ) についてのスピーチがありましたが、Customer最新のコレクション全体 ( ) を取得したいので質問していますIList<Project>

次に、プロファイルに接続された新しいプロジェクトを取得しているときに、インデックス付きのプロファイルに沿って同時に検索したい場合 (ID がないため)、たとえば次のようにします (そのような構成は許可されていません)。

var profile = session.Include<Project>(x => x.Id)
                     .Query<Profile>()
                     .Single(x => x.User == "jwa");   

何らかの方法で行うことはできますか、または以下のように「自分で」最新のプロジェクトを取得する必要がありますか?

var profile = session.Query<Profile>().Single(x = x.User == "jwa");
var projectsIds = profile.FavoriteProjects.Select(x => x.Id).ToList();
var projects = session.Load<Project>(projectsIds);

よりリレーショナルになるように再設計しますか?

4

1 に答える 1

1

申し訳ありませんが、あなたの質問に従うのは難しいですが、あなたのシナリオに対してより一般的な回答を提供しようとします.

インクルード機能の目的は、最初のリクエストで ID を取得したドキュメントを取得するために、データベースへの後続のリクエストを不要にすることです。次のようなモデルがあるとします。

public class Project
{
    public string Id { get; set; }
    public string Name { get; set; }
}

public class Profile
{
    public string Id { get; set; }
    public string Username { get; set; }
    public IList<string> FavoriteProjectIds { get; set; }
}

プロファイルをロードしたい場合は、次のようにします。

var profile = session.Load<Profile>("profiles/daniel");

これにより、このユーザーのお気に入りのすべてのプロジェクトの ID を含むプロファイル ドキュメントが得られます。プロジェクト名のリストを表示したいとしましょう。次のようにします。

var favoriteProjects = session.Load<Project>(profile.FavoriteProjectIds);

これは問題なく機能しますが、データベースに対して 2 つの要求が生成されます。組み込みモードで実行している場合、これは問題ではありませんが、リモートの ravendb サーバーを使用している場合は、2 番目の http 要求は必要ないため、削除した方がよいでしょう。この.Include<T>()機能は便利です:

var profile = session.Include<Profile>(x => x.FavoriteProjectIds)
                     .Load("profiles/daniel");
var favoriteProjects = session.Load<Project>(profile.FavoriteProjectIds);

このコードはデータベースに 1 回だけアクセスするため、高速です。Include 呼び出しで型パラメーターをどのように指定したかに注意してください。これは、パラメーターでラムダ式をサポートする必要があるためであり、含まれるドキュメントの型とは関係ありません。

これは、Include を使用してどのように機能するかです。シンプルにするために、このアプローチを使用することをお勧めします。本当に最大のパフォーマンスを得たい場合、またはこのアプローチを使用しない他の理由がある場合 (プロファイルとプロジェクトが同じシャードに存在しないシャード環境など) 、プロジェクトの一部をプロファイルに非正規化できます。 .

ここで注意すべき重要なことは、プロファイル ドキュメント内のプロジェクト ドキュメント全体を非正規化したくないということです。アプリケーションのどこかにユーザーのプロフィール ページを表示する必要があるとします。このページでは、ユーザーのお気に入りのプロジェクトのリストも表示します。そのリストを表示するために本当に必要なものは何ですか?

この場合、適切な html リンクを作成するためにプロジェクト名を非正規化するだけで済みます (ID は取得できます)。コードで言えば、次のようなクラスがあるとします。

public class DenormalizedProject
{
    public string Id { get; set; }
    public string Name { get; set; }
}

...そして、プロファイルクラスには次のようなプロパティが含まれます...

public IList<DenormalizedProject> FavoriteProjects { get; set; }

このアプローチを使用すると、プロファイル ページを 1 つのドキュメントに表示するために必要なものがすべて揃っており、その情報を取得するためにインクルードを使用する必要さえありません。ただし、これにはコストがかかります。非正規化されたプロジェクト名を維持する必要があります。不変の場合は問題ありませんが、ほとんどの場合、ユーザーはそれを変更できます。次に、非正規化されたすべての参照も更新されるようにする必要があります (バッチ コマンドを使用するか、含まれているすべてのドキュメントを読み込んで更新するだけです)。これは、非正規化アプローチを採用する前に必ず考慮しておきたいことです。

于 2012-05-13T21:23:15.133 に答える