Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You won't actually get the answer you hope for, simply because it is not possible. (N)Hibernate is an Object-Relational-Mapping framework and support <a href="http://docs.jboss.org/hibernate/core/3.3/reference/en/html/inheritance.html" rel="nofollow noreferrer">three kinds of mapping</a> strategies:</p> <ul> <li>table per class hierarchy</li> <li>table per subclass</li> <li>table per concrete class</li> </ul> <p>It also allows you to deviate from this by using <code>formula</code> or <code>sql-insert</code> etc, but as you've found out, these only cause you more pain in the end, are not encouraged by the Hibernate community and are bad for the maintainability of your code.</p> <h3>Solution?</h3> <p>Actually, it is very simple. You do not want to use a class for <code>Role</code>. I assume you mean that you do not want to <em>expose</em> a class of type Role and that you do not want to have to type <code>prObject.Role.Name</code> all the time. Just <code>prObject.Role</code>, which should return a string. You have several options:</p> <ol> <li>Use an inner class in, say, PersonRole, this class can be internal or private. Add a property Role that sets and updates a member field;</li> <li>Use an internal class. Add a property Role that sets and updates a member field;</li> </ol> <p>Let's examine option 2:</p> <pre><code>// 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 */ } } } </code></pre> <p>And the mapping can look as expected. Result: you have not violated the one-table-per-class rule (<em>EDIT: asker says that he explicitly wants to violate that rule, and Hib supports it, which is correct</em>), but you've hidden the objects from modification and access by using typical object oriented techniques. All NH features (cascade etc) still work as expected.</p> <p>(N)Hibernate is all about this type of decisions: how to make a well thought-through and safe abstraction layer to your database without sacrificing clarity, brevity or maintainability or violating OO or ORM rules.</p> <hr> <h3>Update (after q. was closed)</h3> <p>Other excellent approaches I use a lot when dealing with this type of issue are:</p> <ul> <li><p>Create your mappings normally (i.e., one-class-per-table, I know you don't like it, but it's for the best) and use extension methods:</p> <pre><code> // 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; } </code></pre></li> <li><p>Create your mappings normally but use <code>partial class</code>es, which enable you to "decorate" your class any which way you like. The advantage: if you use generated mapping of your tables, you an regenerate as often as you wish. Of course, the partial classes should go in separate files so considering your wish for diminishing "bloat" this probably isn't a good scenario currently.</p> <pre><code> public partial class PersonRole { public string Role {...} } </code></pre></li> <li><p>Perhaps simplest: just overload <code>ToString()</code> for <code>Role</code>, which makes it suitable for use in <code>String.Format</code> and friends, but of course doesn't make it assignable. By default, each entity class or POCO should have a <code>ToString()</code> overload anyway.</p></li> </ul> <p>Though it is possible to do this with NHibernate directly, the q. has been closed before I had time to look at it (no ones fault, I just didn't have the time). I'll update if I find the time to do it through Hibernate HBM mapping, even though I don't agree to the approach. It is not good to wrestle with advanced concepts of Hib when the end result is less clear for other programmers and less clear overall (where did that table go? why isn't there a IDao abstraction for that table? See also <a href="http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx" rel="nofollow noreferrer">NHibernate Best Practices</a> and <a href="http://code.google.com/p/sharp-architecture/" rel="nofollow noreferrer">S#arp</a>). However, the exercise is interesting nevertheless.</p> <p>Considering the comments on "best practices": in typical situations, it shouldn't be only "one class per table", but also one IDaoXXX, one DaoConcreteXXX and one GetDaoXXX for each table, where you use class/interface hierarchy to differentiate between read-only and read/write tables. That's a minimum of four classes/lines of code per table. This is typically auto-generated but gives a very clear access layer (dao) to your data layer (dal). The data layer is best kept as spartan as possible. Nothing of these "best practices" prevent you using extension methods or partial methods for moving <code>Role.Name</code> into <code>Role</code>.</p> <p>These are best <em>general</em> practices. It's not always possible or feasible or even necessary in certain special or typical sitations.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload