I have a [Flags] enum that I would like to store in the database as an int (which as I understand it is the default behavior for enums with the [Flags] attribute). I have some request/response DTOs with properties of that enum type as well, but for these I want to serialize/deserialize the enum as a list of strings (so that the client doesn’t need to know the underlying int value of each flag in the enum).
When I configure JsConfig<T>.RawSerializeFn and JsConfig<T>.RawDeserializeFn to handle the conversion to and from string arrays for that enum type, the DTOs perform the conversion fine, but saving to the database starts failing with System.FormatException: Input string was not in a correct format I assume because those functions are also being applied to the enum when serializing to the database.
Is there an easy way around this (ie, some way to configure different serialization/deserialization behavior for the same type unde OrmLite and the rest of ServiceStack)? I could create my own extension methods to handle the conversion, but I feel like that would add a bunch of extra boilerplate/cruft to all my services that use that enum type in the DTO.
No there’s no distinct configuration of [Flag] Enums that can be configured differently in OrmLite and JsonSerializer.
But there’s already a Enum.ToList() extension method you can use to map a Flag enum to a List<string> so you can easily map it when you return a DTO, e.g:
return new Response {
EnumsList = myEnum.ToList()
}
This raises another question for me–is there an easy way to do that kind of property conversion in an AutoQuery service? For example, if I had a setup like this:
[Flags]
public enum SmurfProperty {
Smart = 0x1,
Angry = 0x2,
Timid = 0x4
}
public class Smurf {
public Guid Id { get; set; }
public string Name { get; set; }
public SmurfProperty Properties { get; set; }
}
public class GetSmurfs : AutoQuery<Smurf> {}
…but I wanted the Properties field to serialize as a list in the response, what is the shortest path to make that happen? Here’s what I would have added currently, am I missing anything that could make this a little less verbose?:
public class SmurfResponse {
public Guid Id { get; set; }
public string Name { get; set; }
public List<string> Properties { get; set; }
}
public class GetSmurfs : AutoQuery<Smurf, SmurfResponse> {}
public class SmurfService : Service
{
public IAutoQuery AutoQuery { get; set; }
public QueryResponse<SmurfResponse> Get(GetSmurfs request)
{
using(var db = DbFactory.OpenDbConnection()) {
var query = AutoQuery.CreateQuery(request, Request.GetRequestParams());
return new QueryResponse<SmurfResponse> {
Offset = query.Offset.GetValueOrDefault(0),
Total = (int) db.Count(query),
Results = db.Select<Smurf>(query).Select(s => new SmurfResponse {
Id = s.Id,
Name = s.Name,
Properties = s.Properties.ToList()
}
}
}
}
}
Since it’s stored as in int in the database when AutoQuery/OrmLite goes to map it to a different Model it’s trying to map an int (i.e. not the Enum).
One way that should work is to have a calculated property (and if you want you can ignore the existing Enum), e.g:
public class SmurfResponse
{
public Guid Id { get; set; }
public string Name { get; set; }
[IgnoreDataMember]
public SmurfProperty Properties { get; set; }
public List<string> PropertyNames { get { return Properties.ToList(); } }
}
This solution should work without needing a custom AutoQuery impl.
After testing a bit, it looks like the ToList() extension method on enums returns a list of all possible flags in the base enum type, and not just the flags that are set in the current value.
For example, I would have expected SmurfProperty.Smart.ToList() to return ["Smart"], but instead it looks like it would return ["Smart", "Angry", "Timid"] (and return that same thing no matter the combination of flags you call ToList() on). Which is OK because I already had my own extension method that behaves the way I expected, but I just thought I’d mention it since it seems to be working differently than the way you had implied (and may be a bug).
Yep thx for the update, was just an Enum Extension I found after a quick scan, didn’t bother checking the impl - it returns all the enum names for that Enum as you’ve noticed