それが不可能であるという理由だけで、あなたは実際にあなたが望む答えを得ることができません。(N)Hibernateはオブジェクトリレーショナルマッピングフレームワークであり、次の3種類のマッピング戦略をサポートします。
- クラス階層ごとのテーブル
- サブクラスごとのテーブル
- 具体的なクラスごとのテーブル
formula
また、 orなどを使用してこれから逸脱することもできますがsql-insert
、ご存知のとおり、これらは最終的にはより多くの苦痛を引き起こし、Hibernateコミュニティによって奨励されておらず、コードの保守性に悪影響を及ぼします。
解決?
実際、それは非常に簡単です。のクラスを使用したくないRole
。Role型のクラスを公開したくないこと、および常に型指定する必要がないことを意味していると思いますprObject.Role.Name
。ただprObject.Role
、文字列を返す必要があります。いくつかのオプションがあります。
- たとえば、PersonRoleで内部クラスを使用します。このクラスは、内部クラスでもプライベートクラスでもかまいません。メンバーフィールドを設定および更新するプロパティRoleを追加します。
- 内部クラスを使用します。メンバーフィールドを設定および更新するプロパティRoleを追加します。
オプション2を調べてみましょう。
// mapped to table Role, will not be visible to users of your DAL
// class can't be private, it's on namespace level, it can when it's an inner class
internal class Role
{
// typical mapping, need not be internal/protected when class is internal
// cannot be private, because then virtual is not possible
internal virtual int Id { get; private set; }
internal virtual string Name { get; set; }
}
// the composite element
public class PersonRole
{
// mapped properties public
public virtual Person Person { get; set; }
// mapped properties hidden
internal virtual Role dbRole { get; set; }
// not mapped, but convenience property in your DAL
// for clarity, it is actually better to rename to something like RoleName
public string Role /* need not be virtual, but can be */
{
get
{
return this.dbRole.Name;
}
set
{
this.dbRole.Name = value; /* this works and triggers the cascade */
}
}
}
そして、マッピングは期待どおりに見える可能性があります。結果:クラスごとに1つのテーブルのルールに違反していません(編集:askerは明示的にそのルールに違反したいと言っており、Hibはそれをサポートしています、これは正しいです)が、オブジェクトを変更およびアクセスから非表示にしました典型的なオブジェクト指向技術を使用することによって。すべてのNH機能(カスケードなど)は引き続き期待どおりに機能します。
(N)Hibernateは、このタイプの決定に関するものです。明確さ、簡潔さ、保守性を犠牲にしたり、OOまたはORMのルールに違反したりせずに、データベースに対してよく考え抜かれた安全な抽象化レイヤーを作成する方法です。
更新(q。が閉じられた後)
このタイプの問題に対処するときに私がよく使用する他の優れたアプローチは次のとおりです。
通常どおりにマッピングを作成し(つまり、テーブルごとに1つのクラス、気に入らないことはわかっていますが、最適です)、拡張メソッドを使用します。
// trivial general example
public static string GetFullName(this Person p)
{
return String.Format("{0} {1}", p.FirstName, p.LastName);
}
// gettor / settor for role.name
public static string GetRoleName(this PersonRole pr)
{
return pr.Role == null ? "" : pr.Role.Name;
}
public static SetRoleName(this PersonRole pr, string name)
{
pr.Role = (pr.Role ?? new Role());
pr.Role.Name = name;
}
通常どおりマッピングを作成しますが、partial class
esを使用すると、クラスを好きなように「装飾」できます。利点:生成されたテーブルのマッピングを使用する場合、必要な頻度で再生成します。もちろん、部分的なクラスは別々のファイルに入れる必要があるので、「肥大化」を減らしたいというあなたの願いを考えると、これはおそらく現在のところ良いシナリオではありません。
public partial class PersonRole
{
public string Role {...}
}
おそらく最も単純です。をオーバーロードするだけで、友人や友人での使用に適していますToString()
が、もちろん割り当て可能にはなりません。デフォルトでは、各エンティティクラスまたはPOCOにはとにかくオーバーロードが必要です。Role
String.Format
ToString()
NHibernateを使用してこれを直接行うことは可能ですが、q。私がそれを見る時間がなくなる前に閉鎖されました(誰のせいでもありません、私には時間がありませんでした)。アプローチに同意しませんが、HibernateHBMマッピングを介してそれを行う時間が見つかった場合は更新します。最終結果が他のプログラマーにとってあまり明確でなく、全体的にあまり明確でない場合、Hibの高度な概念に取り組むのは良くありません(そのテーブルはどこに行きましたか?なぜそのテーブルのIDao抽象化がないのですか?NHibernateのベストプラクティスとS#arp)。ただし、それでも演習は興味深いものです。
「ベストプラクティス」に関するコメントを検討します。通常の状況では、「テーブルごとに1つのクラス」だけでなく、テーブルごとに1つのIDaoXXX、1つのDaoConcreteXXX、および1つのGetDaoXXXを指定し、クラス/インターフェイス階層を使用して区別します。読み取り専用および読み取り/書き込みテーブル。これは、テーブルごとに最低4つのクラス/コード行です。これは通常自動生成されますが、データレイヤー(dal)への非常に明確なアクセスレイヤー(dao)を提供します。データレイヤーは、可能な限り質素に保つのが最適です。Role.Name
これらの「ベストプラクティス」のいずれも、に移動するための拡張メソッドまたは部分メソッドの使用を妨げるものではありませんRole
。
これらはベストジェネラルプラクティスです。特定の特別な場所や典型的な場所では、常に可能または実行可能であるとは限りません。