These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: modeling enumerations - best practices?
PostPosted: Mon Feb 26, 2007 4:40 pm 
Beginner
Beginner

Joined: Thu Nov 02, 2006 5:11 pm
Posts: 32
Location: Toronto
I'm trying to decide on the best approach to modeling enumerations (talking at the conceptual level, not necessarily using a C# enum, although this is one possibility) with NHibernate.

Approach #1. My first design was using the C# enum construct and the NHibernate EnumStringType to save the value of the enum as a string in the DB. However, I would also like to store additional data about each enumerated value, such as a display string and a description, in an associated DB table, and ideally would like a foreign key reference between the table that uses the enum and the lookup table. (The reason for this is so that the DB can be self contained, without relying on the application to provide display strings in the form of resources). The NHibernate schema generator cannot add this reference automatically, because with this design NHIbernate is not aware of the relationship between the 2 tables.

Approach #2. My second design was to model the enumeration as a class (rather than an enum) with static instances, as was common practice in Java. By modeling it as a class, I can have the code, display string, and description all contained in one object, which is nice, and then use a many-to-one reference in the referring class. Also, it can be mapped as an NHibernate class, which solves the missing foreign key problem, because now it is a true many-to-one relationship that NHibernate understands. However, it doesn't feel quite right not to be using the C# enum construct since that is the accepted practice.

I am wondering if anyone else had tried #2 and can comment on the viability of this solution. Alternatively, does anyone have any better ideas?

Thanks,
jr


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 26, 2007 6:40 pm 
Senior
Senior

Joined: Mon Aug 21, 2006 9:18 am
Posts: 179
I very commonly implement your number 2 solution, with static fields returning the 'enumeration'. This makes up for the anemic enum implementation in C#. Only difference tho is that I use thse as ValueObjects and so are components within my classes (usually) and not fullout mapped classes.

_________________
If this helped...please remember to rate it!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 27, 2007 11:47 am 
Newbie

Joined: Mon Jul 18, 2005 7:45 am
Posts: 16
mnichols wrote:
I very commonly implement your number 2 solution, with static fields returning the 'enumeration'. This makes up for the anemic enum implementation in C#. Only difference tho is that I use thse as ValueObjects and so are components within my classes (usually) and not fullout mapped classes.


Hi - We've spend considerable time thinking about this type of issue in our domain. Can you explain your comments a bit further?

e.g. I have a DB table Client with a column TitleID which is an FK into a Title lookup table containing TitleID and Description.

Mapping Client.Title as a many-to-one association is straight-forward, but how can I map Title as a component? (and still get the Description value form the lookup table)

many thanks

Simon


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 27, 2007 2:54 pm 
Senior
Senior

Joined: Sat Sep 10, 2005 3:46 pm
Posts: 178
If you want to store the data in the database then I dont think you will have any other choice than to go with approach 2 but use it as a value object which mnichols describes. Or I guess you could have a many to one assosciation and just cache the objects since the data will most likely never change, but then you have to have a full blown entity.

Another alternative if you can get by without storing the data in the database is to use predefined or custom attributes on your enum values. For example you could use System.ComponentModel.DescriptionAttribute to do something like this:

Code:
public enum Color
{
   [Description("Cool Red")]
   Red,
   
   [Description("Awesome Yellow")]
   Yellow,
   
   [Description("Groovy Green")]
   Green
}


You would need a wrapper or helper class that could read the attributes. If you use a wrapper you copuld have your entity return a reference to the wrapper as opposed to the enum.

Code:
public class ColorWrapper{

  Color _value;
  string _description;

  public ColorWrapper(Color value){
    this._value = value;
  }

  public Color Value{
    get{return this._value;}
  }
 
  public string Description{
    get{
     if(this._description == null){
       FieldInfo fi= typeof(Color).GetField(this._value.ToString());
       DescriptionAttribute[] attributes =
         (DescriptionAttribute[])fi.GetCustomAttributes(
         typeof(DescriptionAttribute), false);
        this._desciption =  (attributes.Length>0)?attributes[0].Description:string.Empty
     }
     
     return this._description;
   }
  } 
}


You could add as many attributes as you need. Just a thought.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 27, 2007 8:36 pm 
Senior
Senior

Joined: Mon Aug 21, 2006 9:18 am
Posts: 179
@Simon,
My decision in the case you provided would be determined by how many Titles I need to 'enumerate' and if they are subject to frequent addition/change/removal. If they are not, I would definetly do something like this:
Code:
    [Serializable]
    public sealed class Title
    {
        private string _name;

        public string Name
        {
            get { return _name; }
        }

        private Title(string name)
        {
            _name = name;
        }

        public static readonly Title ADMIN = new Title("Administrator");
        public static readonly Title KING = new Title("King");
        public static readonly Title GEEK= new Title("Geek");


        public override int GetHashCode()
        {
            int result = _name.GetHashCode();
            result = 29*result + _name.GetHashCode();
            return result;
        }

        public override bool Equals(object obj)
        {
            if (this == obj) return true;
            Title val = obj as Title;
            if (obj == null) return false;
            if (!Equals(_name, val._name)) return false;
            return true;
        }
       
    }

Then as a component within you 'Client' class you'd have
Code:
<component name="Title" class="ValueObjects.Title" access="field.camelcase-underscore">
<property name="Name"/>
</component>

When I use this in code I simply can use Title.ADMIN or Title.KING or whatever. Remember that ValueObjects are not concercned about normalization...their values, not their identities, are important and so may be duplicated over and over in the table.
Hope this helps...

MIKE

_________________
If this helped...please remember to rate it!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 01, 2007 12:01 pm 
Beginner
Beginner

Joined: Thu Nov 02, 2006 5:11 pm
Posts: 32
Location: Toronto
Thanks for the replies - good to know I'm not the only one who has had to spend some time thinking about this issue.

mnichols solution seems like a good one in terms of performance- the only drawback I can see is that if one of the "lookup" values needs to change, you would have to update every record in the table that contains the component-mapped enumeration, because there is no lookup table when using a component mapping.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 01, 2007 12:21 pm 
Senior
Senior

Joined: Mon Aug 21, 2006 9:18 am
Posts: 179
That's true and why I only use this approach for fairly static values. However, running a quick UPDATE in sql is worth the time savings from maintaining another association just for the 'what if this changes' mindset.
Good luck
MIKE

_________________
If this helped...please remember to rate it!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.