ISession.Load が返すものと同様のオブジェクト プロキシを作成したいのですが、いくつかのフィールドが初期化されています。他のプロパティの場合、アクセスすると、プロキシはデータベースからオブジェクト全体を取得します。次の例を検討してください。
public class User
{
protected User() {
}
public User(int id, string username, string email) {
// ...
}
// initialize the following fields from other datasources
public virtual int Id { get; set; }
public virtual string UserName { get; set; }
public virtual string Email { get; set; }
// the rest of fields when accessed will trigger a select by id in the database
public virtual string Field1 { get; set; }
public virtual string Field2 { get; set; }
public virtual DateTime Field3 { get; set; }
public virtual ISet<Comment> Comments { get; set; }
}
私の場合、Id、UserName、Email はよく知られているので、これらのフィールドを含むオブジェクト プロキシを作成し、他のフィールドについてはデフォルトのプロキシ動作のままにします。この ID がデータベースに見つからない場合に例外をスローするだけでなく、事前に初期化されたフィールドが一致しない場合、またはそれらをサイレントに上書きする場合に例外をスローすることもできます。プロキシ ファクトリに NHibernate.ByteCode.Castle を使用しています。
編集:これの目的は、他の場所でクエリできるエンティティからいくつかの投影プロパティを取得できるようにすること (たとえば、lucene インデックス)、およびデータベース呼び出しを回避することです。次に、これらのプロパティのサブセットのみを含むカスタム コンポーネント クラスでこれらのフィールドをラップする代わりに、プロキシ オブジェクトを直接使用して、必要に応じて残りのフィールドをロードできるようにします。最良のシナリオでは、データベースにまったくアクセスしませんが、いくつかのまれなケースでは、他のフィールドにもアクセスしたいと考えています。SELECT N+1 問題の影響は、バッチ処理を使用することで大幅に軽減できます。私が使用したい仮想バージョンのコードは次のようになります。
// create User object proxy with some fields initialized
var user = Session.Load<User>(5, new { UserName = "admin", Email = "admin@company.com" });
Console.WriteLine(user.Id); // doesn't hit the database
Console.WriteLine(user.UserName); // doesn't hit the database
Console.WriteLine(user.FullName); // doesn't hit the database
if (somecondition) {
Console.WriteLine(user.Field1); // fetches all other fields
}