2012-08-31 14 views
25

OK, esto es un poco largo/oscuro, pero me da un error extraño en una situación específica donde uso un Enum como clave de tabla e intento de consulta contra la tabla al tiempo que incluye más de una entidad relacionada de muchos a muchos.Enum como clave en el marco de la entidad 5 error de lanzamiento en muchas combinaciones

El error, desde el código de ejemplo a continuación es:

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

En un proyecto web .NET 4.5, I tienen la siguiente configuración entidad:

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

En el Global.asax.cs solicito inicializar la base de datos:

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

Entonces, trato de consulta en la base de datos:

var context = new EnumTestContext(); 

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

Otras consultas donde utilizo una sola incluyen cargar los datos esperados sin problema. La consulta anterior, con dos incluye arroja el error anterior. En la base de datos veo tablas de combinación autogeneradas (MenuDiets y RecipeDiets) y todos los datos parecen correctos. De nuevo, como en los ejemplos anteriores, puedo consultar los datos pero no puedo incluir varias entidades relacionadas sin arrojar el error.

Si cambio de la última consulta para utilizar solamente un solo incluyen, puedo cargar la otra mesa sin ningún problema:

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

adicional - aunque esto no satisface mi caso de uso como quiero para restringir la mesa sólo a los valores de enumeración y restricciones únicas no son compatibles con EF - esto funcionará si cambio de la clase de entidad dieta utilizar una clave de identidad separada, en lugar de la clave de enumeración:

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

Otra posible solución exploré era crear explícitamente las tablas de unión (MenuDiet s y RecipeDiets) para que la clave de propiedad join se haya tipeado como Enum, pero esto aún devuelve el error anterior.

Parece que realmente son las múltiples inclusiones las que provocan que se ahogue. ¿Alguna idea sobre si estoy haciendo algo mal en la configuración del modelo? La consulta en sí? ¿Un error en Entity Framework?

+0

Por qué la FC de la dieta tienen el tipo de DietIs? ¿No es Diet la tabla de referencias cruzadas? – zsong

+0

Bueno, en este ejemplo, quiero agregar algo de información sobre dietas particulares, por ejemplo, describo Vegan, describo Gluten-Free, etc. También quiero restringir los posibles valores a los de la enumeración que uso en el código, y también me pongo No quiero tener que lanzar hacia adelante y hacia atrás desde un int. –

+0

Pero el PK de ese objeto de dieta debe ser simplemente un entero regular. Y supongo que definiste la relación de clave externa usando FluentAPI. – zsong

Respuesta

5

El problema parece ser el hecho de que enum en .NET es un tipo de clase. De la definición en this page:

Proporciona la clase base para las enumeraciones.

Y esta observación:

Una enumeración es un conjunto de constantes con nombre cuyo tipo subyacente es cualquier tipo integral. Si no se declara explícitamente ningún tipo subyacente, se utiliza Int32 . Enum es la clase base para todas las enumeraciones en .NET Framework.

Sí Define un conjunto de constantes cuyo tipo es un tipo entero, pero cuando se declara yor clave:

public DietIs DietIs { get; set; } 

tu clave es en realidad un tipo de clase de un tipo entero; Es posible que tenga que lanzarlo al comparar o asignar valores de tipo integral. La página proporciona este ejemplo acerca de las conversiones:

Puede convertir entre un miembro de la enumeración y su subyacente tipo mediante el uso de un operador de fundición (en C#) o la conversión (en Visual Basic). El siguiente ejemplo utiliza operadores de conversión o conversión para realizar conversiones tanto de un número entero a un valor de enumeración como de un valor de enumeración a un número entero.

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


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