2

I have the following enum and POCO class

public enum Gender
{
    Male,
    Female,
    Unknown
}

public class Person
{
    public int PersonId { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public Gender? Gender { get; set; }
}

I would like to perform a "get all people" query in my repository such that it would look something like this:

return from p in _db.People
       select new Model.Person
       {
          PersonId = p.PersonId,
          LastName = p.LastName,
          FirstName = p.FirstName,
          Gender = p.Gender,
       };

Unfortunately I get an error "Cannot implicitly convert type 'string' to 'Model.Gender'"

I would like to convert the string which is being queried from the entity framework to my Gender enum and assign it to my POCO class.

4 Answers 4

4

Enums are not supported in Entity Framework. There is a workaround by Alex James, but it's quite involved.

Instead, i prefer to do this:

public enum Gender : byte
{
    Male = 1,
    Female,
    Unknown
}

public class Person
{
    public int PersonId { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public byte Gender { get; set; } // this is the EF model property
    public Gender GenderType // this is an additional custom property
    { 
        get { return (Gender) Gender; }
        set { Gender = (byte)value; }
    }
}

It's basically a hook/wrapper for the actual value. In your database, store Gender as a tinyint (which maps to byte on the conceptual side).

Then you can use a byte enum to map to and from the model property:

return from p in _db.People
       select new Model.Person
       {
          PersonId = p.PersonId,
          LastName = p.LastName,
          FirstName = p.FirstName,
          Gender = p.Gender, // sets byte
       };

But then if you access that ViewModel, because your setting the byte field for Gender, you will also have access to the enum property GenderType.

Does that solve your problem?

Sign up to request clarification or add additional context in comments.

2 Comments

Hey this helps out a lot. Its too bad it pollutes the POCO but that will have to do for now. I wasn't getting much luck with the fake ENUM solution because of the dependency inversion pattern I'm using. I'm sorry I can't vote you're answer up as I do not have enough rep. Thank you very much though.
No problems, please tick one of the answers as correct (whichever one solved your problem). Also, if you don't want to "pollute the POCO", you could put it in a partial class, or you could create an extension method. Still, nothing wrong with having the property there (i do). Don't want your domain model to become anemic.
1

The Entity Framework that I am familiar with does not provide support for enums. EF uses your query expression to create an SQL statement that it then sends to the server, if it cannot create the SQL equivalent of some operation it will throw a NotSupportedException for that operation. If you are expecting to return a small set of data you can separate from the Entity Framework by creating an object in memory using the ToArray method.

var myEntities = (from entity in _db.Entities
                  where /* condition */
                  select entity)
                        .ToArray();

This will create a sequence of entities in memory. Any further query statements will then be in the realm of LINQ to Objects which allows parsing of strings into enums:

return from myEntity in myEntities
       select new MyDataContract
       {
            ID = myEntity.ID,
            Gender g = (Gender)Enum.Parse(typeof(Gender), myEntity.Gender, true)
       };

Or you could even break it out into a foreach loop:

List<MyDataContract> myDataContracts = new List<MyDataContract>();
foreach (var myEntity in myEntities)
{
    var dataContract = new MyDataContract { ID = myEntity.ID };

    if (Enum.IsDefined(typeof(Gender), myEntity.Gender))
        dataContract.Gender = (Gender)Enum.Parse(typeof(Gender), myEntity.Gender, true);

        myDataContracts.Add(dataContract);
}

return myDataContracts.AsEnumerable();

Comments

0
   if (Enum.IsDefined(typeof(Gender), genderstring))
      Gender g = (Gender) Enum.Parse(typeof(Gender), genderstring, true);
   else
      //Deal with invalid string.

1 Comment

This also gives me an exception of type NotSupportedException with error message "LINQ to Entities does not recognize the method 'System.Object Parse(System.Type, System.String)' method, and this method cannot be translated into a store expression."
0

try

Gender = p.Gender != null ? (Gender)Enum.Parse(typeof(Gender), p.Gender) : (Gender?)null;

To parse the string as one of the enums

here's a workaround but it means changing your nice and clean POCO

http://blogs.msdn.com/b/alexj/archive/2009/06/05/tip-23-how-to-fake-enums-in-ef-4.aspx

4 Comments

I just tried this, however it doesn't actually work in the LINQ query. Using Enum.Parse method is what creates the issue. A NotSupportedException occurs with exception message of "LINQ to Entities does not recognize the method 'System.Object Parse(System.Type, System.String)' method, and this method cannot be translated into a store expression."
You're right, I edited the answer with another possible solution/workaround
I'm attempting to do this method of faking enums. Is is possible that you can help with one section. I do not know where to create this "complex type" it looks like it would go in web.config but I'm not certain.
What version of EF are you using? How are you doing POCO (ie. you created an EDMX with the database tables and then during the query you're translating to your POCOs? or did code-first POCOs as in weblogs.asp.net/scottgu/archive/2010/07/23/…)?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.