Storing EnumSet in a database?

前端 未结 10 1799
借酒劲吻你
借酒劲吻你 2020-12-03 21:24

So in C++/C# you can create flags enums to hold multiple values, and storing a single meaningful integer in the database is, of course, trivial.

In Java you have Enu

10条回答
  •  一生所求
    2020-12-03 21:41

    Providing your enum fits into an int (i.e. there are <= 32 values) I would roll my own implementation by using each enum's ordinal value; e.g.

    public > int encode(EnumSet set) {
      int ret = 0;
    
      for (E val : set) {
        // Bitwise-OR each ordinal value together to encode as single int.
        ret |= (1 << val.ordinal());
      }
    
      return ret;
    }
    
    public > EnumSet decode(int encoded, Class enumKlazz) {
      // First populate a look-up map of ordinal to Enum value.
      // This is fairly disgusting: Anyone know of a better approach?
      Map ordinalMap = new HashMap();
      for (E val : EnumSet.allOf(enumKlazz)) {
        ordinalMap.put(val.ordinal(), val);
      }
    
      EnumSet ret= EnumSet.noneOf(enumKlazz);
      int ordinal = 0;
    
      // Now loop over encoded value by analysing each bit independently.
      // If the bit is set, determine which ordinal that corresponds to
      // (by also maintaining an ordinal counter) and use this to retrieve
      // the correct value from the look-up map.
      for (int i=1; i!=0; i <<= 1) {
        if ((i & encoded) != 0) {
          ret.add(ordinalMap.get(ordinal));
        }
    
        ++ordinal;
      }
    
      return ret;
    }
    

    Disclaimer: I haven't tested this!

    EDIT

    As Thomas mentions in the comments the ordinal numbers are unstable in that any change to your enum definition within your code will render the encodings in your database corrupt (e.g. if you insert a new enum value in the middle of your existing definition). My approach to solving this problem is to define an "Enum" table per enumeration, containing a numerical ID (not the ordinal) and the String enum value. When my Java application starts, the first thing the DAO layer does is to read each Enum table into memory and:

    • Verify that all String enum values in the database match the Java definition.
    • Initialise a Bi-directional map of ID to enum and vice-versa, which I then use whenever I persist an enum (In other words, all "data" tables reference the database-specific Enum ID, rather than store the String value explicitly).

    This is much cleaner / more robust IMHO than the ordinal approach I describe above.

提交回复
热议问题