web-dev-qa-db-ja.com

Entity Framework-「タイプ 'Closure type'の定数値を作成できません...」エラー

エラーが発生する理由:

タイプ 'Closure type'の定数値を作成できません。このコンテキストでは、プリミティブ型(Int32、String、Guidなど)のみがサポートされています。

次のLinqクエリを列挙しようとすると?

IEnumerable<string> searchList = GetSearchList();
using (HREntities entities = new HREntities())
{
   var myList = from person in entities.vSearchPeople
   where upperSearchList.All( (person.FirstName + person.LastName) .Contains).ToList();
}

更新:問題を特定するためだけに次のことを試みると、同じエラーが表示されます。

where upperSearchList.All(arg => arg == arg) 

問題はAllメソッドにあるようです。助言がありますか?

79
Gus Cavalcanti

「WHERE ... IN」条件と同等の処理を実行しようとしているようです。 LINQ to Entitiesを使用して「WHERE IN」スタイルのクエリを記述する方法 LINQ to Entitiesでそのタイプのクエリを実行する方法の例について確認してください。

また、この場合、エラーメッセージは特に役に立たないと思います。なぜなら.Containsの後に括弧が続かないため、コンパイラーは述部全体をラムダ式として認識します。

68
Daniel Pratt

過去6か月間、この制限とEF 3.5との戦いに費やしてきましたが、私は世界で最も賢い人ではありませんが、このトピックで役立つ何かがあると確信しています。

高さ50マイルの「ORスタイル」式のツリーを成長させることによって生成されたSQLは、クエリ実行プランの質が低下します。私は数百万行を扱っており、その影響はかなりのものです。

IDで多数のエンティティを探している場合に役立つSQL 'in'を実行するための小さなハックがあります。

private IEnumerable<Entity1> getByIds(IEnumerable<int> ids)
{
    string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray());
    return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
}

ここで、pkIDColumnは、Entity1テーブルのプライマリキーID列名です。

しかし、読んでください!

これは問題ありませんが、検索する必要があるIDを既に持っている必要があります。時々、自分の表現が他の関係に届くようにしたいのですが、私がしているのは、それらの関係の基準です。

時間があれば、これを視覚的に表現しようとしますが、私はこの文をちょっと勉強するだけではありません。Person、GovernmentId、GovernmentIdTypeテーブルを持つスキーマを考えてください。 Andrew Tappert(Person)には、オレゴンからの1つ(GovernmentIdType)とワシントンからの1つ(GovernmentIdType)の2つのIDカード(GovernmentId)があります。

ここから、edmxを生成します。

ここで、特定のID値(1234567など)を持つすべての人を検索するとします。

これは、次のように単一のデータベースヒットで実現できます。

dbContext context = new dbContext();
string idValue = "1234567";
Expression<Func<Person,bool>> expr =
    person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));

IEnumerable<Person> people = context.Person.AsQueryable().Where(expr);

ここにサブクエリがありますか?生成されたSQLは、サブクエリの代わりに「結合」を使用しますが、効果は同じです。最近では、SQL Serverはサブクエリを最適化して、とにかくカバーの下で結合しますが、とにかく...

この動作の鍵は、式内の.Anyです。

11
andrew

エラーの原因を見つけました(Framework 4.5を使用しています)。問題は、EFが「含む」パラメーターで渡される複合型であるため、SQLクエリに変換できないことです。 EFは、int、stringなどの単純型のみをSQLクエリで使用できます...

this.GetAll().Where(p => !assignedFunctions.Contains(p))

GetAllは、複合型のオブジェクトのリストを提供します(例:「関数」)。したがって、ここでは、SQLクエリでこの複雑な型のインスタンスを受信しようとしますが、これは当然機能しません!

検索に適したパラメーターをリストから抽出できる場合、次を使用できます。

var idList = assignedFunctions.Select(f => f.FunctionId);
this.GetAll().Where(p => !idList.Contains(p.FunktionId))

現在、EFには機能する複雑なタイプの「関数」はありませんが、たとえば単純なタイプ(長い)があります。そしてそれはうまくいきます!

8
peter70

.All関数で使用されている配列オブジェクトがnullの場合、このエラーメッセージが表示されます。配列オブジェクトを初期化した後(あなたの場合は、upperSearchList)、エラーはなくなりました。

ここでupperSearchList.All(arg => person.someproperty.StartsWith(arg)))

0
ang