枚举为重点的实体框架5投掷的错误在多对多的连接 [英] Enum as Key in entity framework 5 throwing error on many to many joins

查看:113
本文介绍了枚举为重点的实体框架5投掷的错误在多对多的连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

OK,这是一个有点冗长/晦涩难懂,但我发现了在特定情况下一个奇怪的错误,我用一个枚举作为一个表密钥,并尝试对表的查询,同时包括一个以上的多到多相关实体。

该错误,从例如code以下是:

 键字段'DietIs的类型有望成为MvcApplication8.Models.DietIs,但提供的值类型'System.Int32的实际。
 

在一个.NET 4.5的Web项目中,我有以下实体配置:

 公开枚举DietIs {
    无,
    犹太,
    古,
    素食主义者
}

公共类饮食{

    [键]
    [DatabaseGenerated(DatabaseGeneratedOption.None)
    公共DietIs DietIs {获得;组; }

    公共字符串描述{获得;组; }
    公共虚拟的ICollection<配方>食谱{获得;组; }
    公共虚拟的ICollection<菜单>菜单{获得;组; }
}

公共类食谱{
    公众诠释编号{获得;组; }
    公共字符串名称{;组; }
    公共虚拟的ICollection<饮食>饮食{获得;组; }
}

公共类菜单{
    公众诠释编号{获得;组; }
    公共字符串名称{;组; }
    公共虚拟的ICollection<饮食>饮食{获得;组; }
}

公共类EnumTestContextInit:DropCreateDatabaseAlways< EnumTestContext> {}

公共类EnumTestContext:{的DbContext
    公共DbSet<饮食>饮食{获得;组; }
    公共DbSet<菜单>菜单{获得;组; }
    公共DbSet<配方>食谱{获得;组; }

    公共EnumTestContext():基地(EnumTestContext){
        Configuration.LazyLoadingEnabled = FALSE;
        Configuration.ProxyCreationEnabled = FALSE;
    }
}
 

在的Global.asax.cs文件我初始化数据库:

  Database.SetInitializer(新EnumTestContextInit());
        使用(VAR上下文=新EnumTestContext()){

            VAR noDiet =新的饮食{DietIs = DietIs.None,说明=无论你想要什么};
            VAR paleoDiet =新的饮食{DietIs = DietIs.Paleo,说明=像旧石器时代人民};
            VAR vegDiet =新的饮食{DietIs = DietIs.Vegetarian,说明=无肉};

            context.Menus.Add(新菜单{名称=芝士汉堡薯条菜单,饮食=新的名单,其中,饮食与GT; {noDiet}});
            context.Menus.Add(新菜单{名称=猛犸鞑靼牛排坚果菜单,饮食=新的名单,其中,饮食与GT; {paleoDiet,noDiet}});
            context.Menus.Add(新菜单{名称=大豆奶酪比萨菜单,饮食=新的名单,其中,饮食与GT; {vegDiet,noDiet}});

            context.Recipes.Add(新配方{名称=芝士汉堡,饮食=新的名单,其中,饮食与GT; {noDiet}});
            context.Recipes.Add(新配方{名称=猛犸鞑靼牛排,饮食=新的名单,其中,饮食与GT; {paleoDiet,noDiet}});
            context.Recipes.Add(新配方{名称=奶酪比萨,饮食=新的名单,其中,饮食与GT; {vegDiet,noDiet}});

            context.SaveChanges();
        }
 

于是,我试图对数据库查询:

  VAR上下文=新EnumTestContext();

        VAR dietsWithMenusAndRecipes = context.Diets
                  .INCLUDE(E => e.Menus)
                  .INCLUDE(E => e.Recipes)
                  .ToList();
 

在这里我用一个其它的查询包括加载预期的数据没有问题。上面的查询,有两个包括抛出上述错误。在我看到自动生成的数据库连接表(MenuDiets和RecipeDiets),所有的数据看起来是正确的。此外,如在上面的例子中,我可以查询反对的数据,但不能包括多个相关实体,而不引发错误。

如果我改变的最后一个查询只使用一个单一的包括,我可以加载没有问题的另一个表:

  VAR dietsWithMenusAndRecipes = context.Diets
                 .INCLUDE(E => e.Menus).ToList();

        的foreach(在dietsWithMenusAndRecipes VAR项){
            context.Entry(项目).Collection(E => e.Recipes).Load();
            VAR REC = item.Recipes;
        }
 

另外 - 尽管这不符合我的使用情况下,我想限制只是不支持EF枚举值和唯一约束表 - 这将工作,如果我改变饮食实体类使用一个独立的身份关键的,而不是Enum项:

 公众诠释编号{获得;组; }
    公共DietIs DietIs {获得;组; }
 

另一种可能的解决方案,我探讨是明确创建,使联接财产密钥类型为枚举的连接表(MenuDiets和RecipeDiets),但仍返回上面的错误。

这真的好像是多个包括那些导致其窒息。任何想法,我是否做一些错误的模型设置?查询本身?在实体框架的问题吗?

解决方案

这个问题似乎是一个事实,即枚举在.NET中是一个类类型。从<一个定义href="http://msdn.microsoft.com/en-us/library/system.enum.aspx?cs-save-lang=1&cs-lang=csharp#$c$c-snippet-2">this页面:

  

提供的基类枚举。

这句话:

  

这是枚举一组命名常量的基础类型是   任何整型。如果没有基本类型是显式声明的Int32   用来。枚举是在.NET中的所有枚举的基类   框架。

是的,它定义了一组常量,其类型为一个整数类型,但是当你声明尤尔关键的:

 公共DietIs DietIs {获得;组; }
 

您的关键实际上是一个类类型不是整型;你可能有比较或指定整型值时,投它。该页面提供了有关转换这个例子:

  

您可以枚举成员和它的基础类型之间的转换   通过使用铸造(在C#中)或转换(在Visual Basic)运算符。   下面的示例使用套管或转换操作符来执行   转换时,从一个整数枚举值,从   枚举值的整数。

 公开枚举ArrivalStatus {晚= -1,准时= 0,早= 1};


INT值3 = 2;
ArrivalStatus STATUS3 =​​(ArrivalStatus)值3;
INT值4 =(INT)STATUS3;
 

OK, this is a bit lengthy / obscure, but I'm getting an odd error in specific situation where I use an Enum as a table Key and attempt to query against the table while including more than one many-to-many related entities.

The error, from the example code below is:

The type of the key field 'DietIs' is expected to be 'MvcApplication8.Models.DietIs', but the value provided is actually of type 'System.Int32'.

In a .net 4.5 web project, I have the following entity configuration :

public enum DietIs {
    None,
    Kosher,
    Paleo,
    Vegetarian
}

public class Diet {

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public DietIs DietIs { get; set; }

    public string Description { get; set; }
    public virtual ICollection<Recipe> Recipes { get; set; }
    public virtual ICollection<Menu> Menus { get; set; }
}

public class Recipe {
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Diet> Diets { get; set; }
}

public class Menu {
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Diet> Diets { get; set; }
}

public class EnumTestContextInit : DropCreateDatabaseAlways<EnumTestContext> {}

public class EnumTestContext : DbContext {
    public DbSet<Diet> Diets { get; set; }
    public DbSet<Menu> Menus { get; set; }
    public DbSet<Recipe> Recipes { get; set; }

    public EnumTestContext() : base("EnumTestContext") {
        Configuration.LazyLoadingEnabled = false;
        Configuration.ProxyCreationEnabled = false;
    }
}

In the Global.asax.cs file I initialize the database:

 Database.SetInitializer(new EnumTestContextInit());
        using (var context = new EnumTestContext()) {

            var noDiet = new Diet { DietIs = DietIs.None, Description = "Whatever you want" };
            var paleoDiet = new Diet { DietIs = DietIs.Paleo, Description = "Like paleolithic peoples" };
            var vegDiet = new Diet { DietIs = DietIs.Vegetarian, Description = "No meat" };

            context.Menus.Add(new Menu { Name = "Cheese burger with Fries Menu", Diets = new List<Diet> { noDiet } });
            context.Menus.Add(new Menu { Name = "Mammoth Steak Tartar with Nuts Menu", Diets = new List<Diet> { paleoDiet, noDiet } });
            context.Menus.Add(new Menu { Name = "Soy Cheese Pizza Menu", Diets = new List<Diet> { vegDiet, noDiet } });

            context.Recipes.Add(new Recipe {Name = "Cheese burger", Diets = new List<Diet> {noDiet}});
            context.Recipes.Add(new Recipe { Name = "Mammoth Steak Tartar", Diets = new List<Diet> { paleoDiet, noDiet} });
            context.Recipes.Add(new Recipe { Name = "Cheese Pizza", Diets = new List<Diet> { vegDiet, noDiet } });

            context.SaveChanges();
        }

Then, I attempt to query against the database:

var context = new EnumTestContext();

        var dietsWithMenusAndRecipes = context.Diets
                  .Include(e => e.Menus)
                  .Include(e => e.Recipes)
                  .ToList();

Other queries where I use a single include load the expected data without issue. The query above, with two includes throws the error above. In the database I see autogenerated join tables (MenuDiets and RecipeDiets) and all the data looks correct. Again, as in the examples above I can query against the data but can't include multiple related entities without throwing the error.

If I change the last query to only use a single include, I can load the other table without issue:

        var dietsWithMenusAndRecipes = context.Diets
                 .Include(e => e.Menus).ToList();

        foreach (var item in dietsWithMenusAndRecipes) {
            context.Entry(item).Collection(e => e.Recipes).Load();
            var rec = item.Recipes;
        }

Further — though this does not satisfy my use case as I want to restrict the table to just the enum values and unique constraints aren't supported in EF — this will work if I change the Diet entity class to use a separate identity key, rather than the Enum key:

    public int Id { get; set; }
    public DietIs DietIs { get; set; }

Another possible solution I explored was to explicitly create the join tables (MenuDiets and RecipeDiets) so that the join property key was typed as the Enum, but this still returned the above error.

It really seems to be the multiple Includes that are causing it to choke. Any ideas as to whether I'm doing something wrong in the model setup? The query itself? A bug in Entity Framework?

解决方案

The issue seems to be the fact that enum in .NET is a class type. From the definition on this page:

Provides the base class for enumerations.

And this remark:

An enumeration is a set of named constants whose underlying type is any integral type. If no underlying type is explicitly declared, Int32 is used. Enum is the base class for all enumerations in the .NET Framework.

Yes it defines a set of constants whose type is an integral type but when you declare yor key:

public DietIs DietIs { get; set; }

Your key is actually a class type not an integral type; you may have to cast it when comparing or assigning values of integral type. The page provides this example about conversions:

You can convert between an enumeration member and its underlying type by using a casting (in C#) or conversion (in Visual Basic) operator. The following example uses casing or conversion operators to perform conversions both from an integer to an enumeration value and from an enumeration value to an integer.

public enum ArrivalStatus { Late=-1, OnTime=0, Early=1 };


int value3 = 2;
ArrivalStatus status3 = (ArrivalStatus) value3;
int value4 = (int) status3;

这篇关于枚举为重点的实体框架5投掷的错误在多对多的连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆