25

OK、これは少し長い/あいまいですが、Enum をテーブル キーとして使用し、複数の多対多の関連エンティティを含めてテーブルに対してクエリを実行しようとする特定の状況で奇妙なエラーが発生します。

以下のコード例のエラーは次のとおりです。

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

単一のインクルードを使用する他のクエリは、予想されるデータを問題なくロードします。2 つのインクルードを含む上記のクエリは、上記のエラーをスローします。データベースには、自動生成された結合テーブル (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 エンティティ クラスを別の ID キーを使用するように変更すると機能します。 Enum キーより:

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

私が検討したもう 1 つの解決策は、結合テーブル (MenuDiets と RecipeDiets) を明示的に作成して、結合プロパティ キーが Enum として入力されるようにすることでしたが、それでも上記のエラーが返されました。

それが詰まる原因となっているのは、実際には複数のインクルードのようです。モデルのセットアップで何か間違っているかどうかについてのアイデアはありますか? クエリ自体?Entity Framework のバグですか?

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 に答える