25

好的,这有点冗长/晦涩,但是在我使用枚举作为表键并尝试查询表同时包含多个多对多相关实体的特定情况下,我遇到了一个奇怪的错误。

下面的示例代码中的错误是:

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

在 .net 4.5 web 项目中,我有以下实体配置:

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;
    }
}

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

 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();
        }

然后,我尝试查询数据库:

var context = new 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 (var item in dietsWithMenusAndRecipes) {
            context.Entry(item).Collection(e => e.Recipes).Load();
            var rec = item.Recipes;
        }

此外——尽管这不能满足我的用例,因为我想将表限制为枚举值,并且 EF 不支持唯一约束——如果我将 Diet 实体类更改为使用单独的标识键,这将起作用,而不是比枚举键:

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

我探索的另一个可能的解决方案是显式创建连接表(MenuDiets 和 RecipeDiets),以便将连接属性键键入为 Enum,但这仍然返回上述错误。

确实似乎是导致它窒息的多个包含。关于我是否在模型设置中做错了什么有什么想法吗?查询本身?实体框架中的错误?

4

1 回答 1

5

问题似乎在于enum.NET 中是一个类类型。根据此页面上的定义:

提供枚举的基类。

而这句话:

枚举是一组命名常量,其基础类型是任何整数类型。如果没有显式声明基础类型,则使用 Int32。Enum 是 .NET Framework 中所有枚举的基类。

是的,它定义了一组常量,其类型是整数类型,但是当您声明您的键时:

public DietIs DietIs { get; set; }

您的键实际上是类类型而不是整数类型;在比较或分配整数类型的值时,您可能必须强制转换它。该页面提供了有关转换的示例:

您可以使用强制转换(在 C# 中)或转换(在 Visual Basic 中)运算符在枚举成员及其基础类型之间进行转换。下面的示例使用大小写或转换运算符执行从整数到枚举值以及从枚举值到整数的转换。

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


int value3 = 2;
ArrivalStatus status3 = (ArrivalStatus) value3;
int value4 = (int) status3;
于 2013-03-01T19:45:49.233 回答