Handling enum values with type converters in Windows Azure Mobile Services
Join the DZone community and get the full member experience.
Join For Freei’ve been doing a lot of work with windows azure mobile services (wams). it’s a brilliant technology that allows you to stand up powerful odata compliant services to support your windows 8 store apps, windows phone 8 apps, and even ios apps in just a few minutes. it’s hard to oversell the sheer awesomeness of this stuff.
i’m currently working on a bunch of code that will shortly become a sample project highlighting both wams and windows 8 apps (look for a project called “familypig” coming soon). in the process of building that, i ran into a couple of questions – one of which i’ll cover here, and give some guidance to people who might be running into a similar question.
one of the cool features that makes wams super easy to work with is the concept of “dynamic schema”. in a nutshell, that means that if you have an existing table, and you throw a plain old clr object (poco) at it using the insertasync method (of the imobileservicetable interface), wams is smart enough to look at the object coming in, and make sure that it has all the columns that it needs in the underlying windows azure sql database table to store the record (assuming that “dynamic schema” is enabled on the mobile service). if the column does exist, it gets created on the fly. very, very cool. note, what’s actually happening under the covers is that your poco object is being converted to a json object for transmission over the wire, and wams is pulling apart that json object to look at the columns.
now, in order to do this, it makes some assumptions. it looks at the json object, and if it sees a certain type of data, it creates a certain type of column to support the data. the easiest thing that it could have done would be to just create text columns in the underlying sql database, since any type of data can be stored as a string. instead, it does something quite a bit smarter, and creates data types that are quite a bit more “appropriate”. here’s the strategy that it uses:
json / clr data type | t-sql type in underlying sql azure database table |
numeric values (integer, decimal, floating point) | float(53) – this is the maximum precision float . |
boolean | bit |
datetime | datetimeoffset(3) |
string | nvarchar(max) |
ok, so this is great. dynamic schema is pretty cool. however…
when i work on a database schema, i often run into a case where i want to create a “code/decode” style table. in my world, a “code/decode” table is typically a two column table, where the primary key is the “code” and the other column is a textual description. the canonical example is a “states” table (in the us). like this:
code | decode |
al | alabama |
ak | alaska |
az | arizona |
… | … |
il | illinois |
… | … |
wy | wyoming |
then, with this table defined, i’ll just use it anywhere i need a state… like this:
column | datatype | notes |
firstname | nvarchar(50) | |
lastname | nvarchar(50) | |
address1 | nvarchar(100) | |
address2 | nvarchar(100) | |
city | nvarchar(100) | |
state | char(2) | foreign key to state code |
zipcode | char(5) |
now, in my current project, it wasn’t a state code that i needed, it was a “ currencytype ”. and moreover, i wanted to be able to have an “enum” value of currencytypes to be able to work with in my application. this led me to wonder how wams could handle storing and retrieving an “enum” in the database. it’s not immediately clear that it would know what to do with it as a json type. the javascriptserializer seems to turn enum values into an integer value , which would probably work, but i really wanted my underlying sql table to store “il” for illinois, and not the number 14 as a 53 bits of precision float. so, how can i turn my enum values into the underlying state codes as a 2 character string on the way in, and reconvert them back to my enum values on the way out?
to start with, here’s the (truncated) version of my enum for my currencytype.
public enum currencytype { unitedarabemiratesdirham, afghanistanafghani, albanialek, //... unitedstatesdollar, //... unknown }
next, the secret sauce turns out to be an idatamemberjsonconverter . this interface exists within the microsoft.windowsazure.mobileservices assembly, and has 2 methods that you need to implement – convertfromjson and converttojson . here’s the type converter that i created to massage my enum into a string going in, and from a string back to the enum on the way back out…
first, the converttojson method:
public ijsonvalue converttojson(object instance) { if (instance is types.currencytype) { switch ((types.currencytype)instance) { case types.currencytype.unitedarabemiratesdirham: return jsonvalue.createstringvalue("aed"); case types.currencytype.afghanistanafghani: return jsonvalue.createstringvalue("afn"); case types.currencytype.albanialek: return jsonvalue.createstringvalue("all"); // snip case types.currencytype.unitedstatesdollar: return jsonvalue.createstringvalue("usd"); // snip default: return jsonvalue.createstringvalue("xxx"); } } else return jsonvalue.parse("null"); }
next, the convertfromjson method:
public object convertfromjson(ijsonvalue value) { currencytype result = types.currencytype.unknown; if (value != null && value.valuetype == jsonvaluetype.string) { switch (value.getstring()) { case "aed": return types.currencytype.unitedarabemiratesdirham; case "afn": return types.currencytype.afghanistanafghani; case "all": return types.currencytype.albanialek; // snip case "usd": return types.currencytype.unitedstatesdollar; // snip case "zwd": return types.currencytype.zimbabwedollar; case "xxx": return types.currencytype.unknown; default: return types.currencytype.unknown; } } return result; }
now, the only thing remaining is to decorate the clr class that we’re using to hold our object with enough information to get the serializer to use our type converter as necessary. in my case, the column for currencytype is contained in a class called familygroup.
here’s that implementation:
public class familygroup { public long id { get; set; } public string name { get; set; } [datamemberjsonconverter(convertertype = typeof(currencytypeconverter))] public currencytype currencytype { get; set; } }
and that’s it. we have our enum to work with in our code, we’re able to store and retrieve our values to wams and the data in the tables is readable to boot.
happy coding.
Opinions expressed by DZone contributors are their own.
Trending
-
Using Render Log Streams to Log to Papertrail
-
Revolutionizing Algorithmic Trading: The Power of Reinforcement Learning
-
Personalized Code Searches Using OpenGrok
-
How To Use Geo-Partitioning to Comply With Data Regulations and Deliver Low Latency Globally
Comments