views:

59

answers:

3

What is the best/prettiest/most flexible way of storing application settings with Hibernate?

Is a single row table the way to go, or is there a better way? The ability to store extra settings in the same place/table, but outside of the application domain would be nice.

I've experimented with a Key/Value table, for example:

Key      | Value
-------------------------
width    | 20px
height   | 40px
showall  | true
etc.

But this doesn't seem to fit Hibernate very well.

Any ideas?

+1  A: 

I would suggest that you organize your domain model based on how the values are used (similar to how you would organize any OO model), and then persist those entities. For your example, you would have a Window object with width, height, and showall attributes, which you then persist to the database as a single row/object.

This way you could have the following (hypothetical situation):

id | layoutType | width | height | images
-----------------------------------------------
0  | widescreen | 1000  | 500    | true
1  | normal     | 600   | 500    | true
2  | mobile     | 320   | 480    | false 
Andy
+1  A: 

I have actually implemented this as a key/value pair in C# with nHibernate. The table is the same as you described with just a key/value pairing. When I want to get/set a value my persistence layer accepts the "key" (as an enumeration) and returns a ApplicationSetting object. This object is really just a wrapper for the key/value pair.

Simple Example (in c#):

class ApplicationSetting
{
  private string theApplicationSettingString = string.Empty;

  /// <summary>
  /// The name of the setting.
  /// </summary>
  public virtual ApplicationSettingKey SettingName
  {
     //I use enumerations here so that I'm guaranteed to get a key I
     //already know about and not a random string.
     get
     {
        return (ApplicationSettingKey)Enum.Parse(
           typeof(ApplicationSettingKey), theApplicationSettingString);
     }
     set
     {
        theApplicationSettingString =
           Enum.GetName(typeof(ApplicationSettingKey), value);
     }
  }

  /// <summary>
  /// The value of the setting.
  /// </summary>
  public virtual string SettingValue
  {
     get;
     set;
  }
}



/// <summary>
/// Enumeration for all application settings.
/// </summary>
public enum ApplicationSettingKey
{
     WIDTH,
     HEIGHT,
     SHOWALL
}


/// <summary>
/// Returns the ApplicationSetting from the database that corresponds to 
/// the passed in key/name.
/// </summary>
/// <param name="aKey">The key/name of the Application setting to 
/// retrieve.</param>
/// <returns>The ApplicationSetting Definition that with the corresponding
/// application setting key/name.</returns>
public ApplicationSetting GetApplicationSettingByKey(ApplicationSettingKey aKey)
{
    const string propertyName = "theApplicationSettingString";
    string key = Enum.GetName(typeof(ApplicationSettingKey), aKey);
    DetachedCriteria criteria = DetachedCriteria.For<ApplicationSetting>();
    criteria.Add(Restrictions.Eq(propertyName, key));
    return FindFirst(criteria);
}
brainimus
I ended up using this approach, but I'd recommend anyone reading this to evaluate all the other proposed solutions before here as well as any other existing technique, before making a decision.
Kristoffer
@Kristoffer I completely agree that others should look at all the solutions. This solution was chosen for my project because it fit well with other parts of the project.
brainimus
+2  A: 

To strictly answer your question, you can map a key/value table with Hibernate:

@Entity
public class Settings {
    @Id
    private String key;
    private String value;

    // getters, setters, etc
}

But whether you really need to store this in a database or not, I think I'd go for Commons Configuration instead of Hibernate (or maybe just a Properties object if you don't need the settings to be persited in a database the Preferences API as suggested by @ring).

Pascal Thivent
Rather, `java.util.Preferences` based APIs
ring bearer
@ring good point, answer updated, thanks.
Pascal Thivent