Entity framework 在linq查询MVC 2.0中将字符串解析为poco类枚举

Entity framework 在linq查询MVC 2.0中将字符串解析为poco类枚举,entity-framework,asp.net-mvc-2,enums,asp.net-4.0,Entity Framework,Asp.net Mvc 2,Enums,Asp.net 4.0,我有以下enum和POCO类 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; s

我有以下enum和POCO类

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; }
}
我希望在我的存储库中执行“获取所有人”查询,使其看起来像这样:

return from p in _db.People
       select new Model.Person
       {
          PersonId = p.PersonId,
          LastName = p.LastName,
          FirstName = p.FirstName,
          Gender = p.Gender,
       };
不幸的是,我遇到一个错误,无法将类型“string”隐式转换为“Model.Gender”

我想将正在从实体框架查询的字符串转换为我的性别枚举,并将其分配给我的POCO类。

试一试

将字符串作为枚举之一进行分析

这里有一个解决办法,但它意味着改变你漂亮干净的POCO


实体框架中不支持枚举。亚历克斯·詹姆斯(Alex James)提出了一个变通方案,但涉及面很广

相反,我更喜欢这样做:

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; }
    }
}
它基本上是一个实际值的钩子/包装器。在数据库中,将性别存储为tinyint,它映射到概念侧的字节

然后,可以使用字节枚举映射到模型属性和从模型属性映射:

return from p in _db.People
       select new Model.Person
       {
          PersonId = p.PersonId,
          LastName = p.LastName,
          FirstName = p.FirstName,
          Gender = p.Gender, // sets byte
       };
但是,如果您访问该ViewModel,因为您为性别设置了字节字段,那么您还可以访问枚举属性GenderType


这解决了您的问题吗?

我熟悉的实体框架不支持枚举。EF使用您的查询表达式创建一条SQL语句,然后将其发送到服务器,如果它无法创建某个操作的SQL等价物,它将为该操作抛出NotSupportedException。如果希望返回一小部分数据,可以使用ToArray方法在内存中创建一个对象,从而与实体框架分离

这将在内存中创建一系列实体。然后,任何进一步的查询语句都将位于LINQ to对象领域,该领域允许将字符串解析为枚举:

return from myEntity in myEntities
       select new MyDataContract
       {
            ID = myEntity.ID,
            Gender g = (Gender)Enum.Parse(typeof(Gender), myEntity.Gender, true)
       };
或者您甚至可以将其分解为foreach循环:


我刚刚尝试了这个,但是它实际上在LINQ查询中不起作用。使用Enum.Parse方法是产生问题的原因。出现NotSupportedException,异常消息为LINQ to Entities无法识别“System.Object ParseSystem.Type,System.String”方法,并且无法将此方法转换为存储表达式。没错,我使用另一种可能的解决方案/解决方法编辑了答案。我正在尝试使用此伪造枚举的方法。您可以帮助完成一个部分。我不知道在哪里创建这个复杂的类型,它看起来应该放在web.config中,但我不确定。您使用的是什么版本的EF?您是如何进行POCO ie的。您使用数据库表创建了一个EDMX,然后在查询过程中转换为POCO?还是像中一样先编写POCOs?这也给了我一个NotSupportedException类型的异常,错误消息是LINQ to Entities无法识别“System.Object ParseSystem.type,System.String”方法,并且该方法无法转换为存储表达式。嘿,这帮了大忙。这太糟糕了,它污染了POCO,但现在只能这样了。由于我使用的依赖项反转模式,我在使用伪枚举解决方案时运气不太好。很抱歉,我不能投票支持你的答案,因为我没有足够的代表。非常感谢。没有问题,请在答案中选择一个正确答案,无论哪个答案解决了你的问题。此外,如果您不想污染POCO,可以将其放在分部类中,或者创建一个扩展方法。不过,在那里拥有房产并没有什么错,我是这样做的。不要让你的领域模型变得贫乏。
return from p in _db.People
       select new Model.Person
       {
          PersonId = p.PersonId,
          LastName = p.LastName,
          FirstName = p.FirstName,
          Gender = p.Gender, // sets byte
       };
var myEntities = (from entity in _db.Entities
                  where /* condition */
                  select entity)
                        .ToArray();
return from myEntity in myEntities
       select new MyDataContract
       {
            ID = myEntity.ID,
            Gender g = (Gender)Enum.Parse(typeof(Gender), myEntity.Gender, true)
       };
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();