Does PetaPoco handle enums?
Asked Answered
B

4

18

I'm experimenting with PetaPoco to convert a table into POCOs.

In my table, I've got a column named TheEnum. The values in this column are strings that represent the following enum:

public enum MyEnum
{
    Fred,
    Wilma
}

PetaPoco chokes when it tries to convert the string "Fred" into a MyEnum value.

It does this in the GetConverter method, in the line:

Convert.ChangeType( src, dstType, null );

Here, src is "Fred" (a string), and dstType is typeof(MyEnum).

The exception is an InvalidCastException, saying Invalid cast from 'System.String' to 'MyEnum'

Am I missing something? Is there something I need to register first?

I've got around the problem by adding the following into the GetConverter method:

if (dstType.IsEnum && srcType == typeof(string))
{
  converter = delegate( object src )
            {
                return Enum.Parse( dstType, (string)src ) ;
            } ;
}

Obviously, I don't want to run this delegate on every row as it'll slow things down tremendously. I could register this enum and its values into a dictionary to speed things up, but it seems to me that something like this would likely already be in the product.

So, my question is, do I need to do anything special to register my enums with PetaPoco?

Update 23rd February 2012

I submitted a patch a while ago but it hasn't been pulled in yet. If you want to use it, look at the patch and merge into your own code, or get just the code from here.

Byrne answered 27/7, 2011 at 19:56 Comment(3)
Update Jun. 28, 2012 the exact patch has still not been applied but similar code has been added in the v5 branch. See also toptensoftware.com/Articles/137/…Alcina
If it is not difficult for you, pls submit patch to npoco too. I recommend you to switch to npoco, cause it has more active development and have all features that PetaPoco has and even more.Banal
Update Sept. 9, 2014 @iano answer is the correct one for the lastest 5.0.2 version.Benn
W
5

You're right, handling enums is not built into PetaPoco and usually I just suggest doing exactly what you've done.

Note that this won't slow things down for requests that don't use the enum type. PetaPoco generates code to map responses to pocos so the delegate will only be called when really needed. In other words, the GetConverter will only be called the first time a particular poco type is used, and the delegate will only be called when an enum needs conversion. Not sure on the speed of Enum.Parse, but yes you could cache in a dictionary if it's too slow.

Waziristan answered 27/7, 2011 at 23:18 Comment(3)
Thanks Brad. I'll add enum lookups and submit a patch.Byrne
As per Dec 27, 2011 the patch has not been applied. It will be a nice addition.Biradial
Update Jun. 28, 2012 the exact patch has still not been applied but similar code has been added in the v5 branch. See also toptensoftware.com/Articles/137/…Alcina
T
6

I'm using 4.0.3 and PetaPoco automatically converts enums to integers and back. However, I wanted to convert my enums to strings and back. Taking advantage of Steve Dunn's EnumMapper and PetaPoco's IMapper, I came up with this. Thanks guys.

Note that it does not handle Nullable<TEnum> or null values in the DB. To use it, set PetaPoco.Database.Mapper = new MyMapper();

class MyMapper : PetaPoco.IMapper
{
    static EnumMapper enumMapper = new EnumMapper();

    public void GetTableInfo(Type t, PetaPoco.TableInfo ti)
    {
        // pass-through implementation
    }

    public bool MapPropertyToColumn(System.Reflection.PropertyInfo pi, ref string columnName, ref bool resultColumn)
    {
        // pass-through implementation
        return true;
    }

    public Func<object, object> GetFromDbConverter(System.Reflection.PropertyInfo pi, Type SourceType)
    {
        if (pi.PropertyType.IsEnum)
        {
            return dbObj =>
            {
                string dbString = dbObj.ToString();
                return enumMapper.EnumFromString(pi.PropertyType, dbString);
            };
        }

        return null;
    }

    public Func<object, object> GetToDbConverter(Type SourceType)
    {
        if (SourceType.IsEnum)
        {
            return enumVal =>
            {
                string enumString = enumMapper.StringFromEnum(enumVal);
                return enumString;
            };
        }

        return null;
    }
}
Theodoratheodore answered 6/4, 2012 at 20:11 Comment(0)
W
5

You're right, handling enums is not built into PetaPoco and usually I just suggest doing exactly what you've done.

Note that this won't slow things down for requests that don't use the enum type. PetaPoco generates code to map responses to pocos so the delegate will only be called when really needed. In other words, the GetConverter will only be called the first time a particular poco type is used, and the delegate will only be called when an enum needs conversion. Not sure on the speed of Enum.Parse, but yes you could cache in a dictionary if it's too slow.

Waziristan answered 27/7, 2011 at 23:18 Comment(3)
Thanks Brad. I'll add enum lookups and submit a patch.Byrne
As per Dec 27, 2011 the patch has not been applied. It will be a nice addition.Biradial
Update Jun. 28, 2012 the exact patch has still not been applied but similar code has been added in the v5 branch. See also toptensoftware.com/Articles/137/…Alcina
S
5

If you are using PetaPoco's T4 generation and you want enums in your generated type, you can use the PropertyType override in Database.tt:

tables["App"]["Type"].PropertyType = "Full.Namespace.To.AppType";
Sessoms answered 11/4, 2012 at 21:45 Comment(0)
U
0

I you want to store the value of the enum instead of the index number (1,2,4 for example) you can locate the update function in PetaPoco class because the code is "managed" etc, when you add it as nuget package it will store the .cs file to your project. If we would have the enum variable Color = {red, yellow, blue}

Instead of:

// Store the parameter in the command
AddParam(cmd, pc.GetValue(poco), pc.PropertyInfo);

change to:

//enum?
if (i.Value.PropertyInfo.PropertyType.IsEnum)
{
       AddParam(cmd, i.Value.GetValue(poco).ToString(), i.Value.PropertyInfo);
}
else
{
       // Store the parameter in the command
       AddParam(cmd, i.Value.GetValue(poco), i.Value.PropertyInfo);
}

It would store "yellow" instead of 2

Uniform answered 5/6, 2015 at 15:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.