2016-10-13 6 views
1

DB内にエンティティとしてキー値のペアの一覧がメタデータとして含まれています。メタデータ内の指定された項目を照合してオブジェクトのリストを返したい。Entity FrameworkでLINQ複合オブジェクト検索を実行できません

すなわちオブジェクトがKeyOne、KeyTwoとKeyThreeのメタデータを持つことができる場合、私はABCの 『とKeyThreeが含まれている『ド「をKeyOneが含まれているすべてのオブジェクトを、私を連れ戻す』と言うことができるようにしたい』

これは私のC#でクエリ

var objects = repository.GetObjects().Where(t => 
        request.SearchFilters.All(f => 
         t.ObjectChild.Any(tt => 
          tt.MetaDataPairs.Any(md => 
           md.Key.ToLower() == f.Key.ToLower() && md.Value.ToLower().Contains(f.Value.ToLower()) 
          ) 
         ) 
        ) 
       ).ToList(); 

と、これは

[DataContract] 
public class FindObjectRequest 
{ 
    [DataMember] 
    public IDictionary<string, string> SearchFilters { get; set; } 
} 

そして最後に、私のメタデータPOCO

私の要求クラスです
[Table("MetaDataPair")] 
    public class DbMetaDataPair : IEntityComparable<DbMetaDataPair> 
    { 
     [Key] 
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
     public long Id { get; set; } 

     [Required] 
     public string Key { get; set; } 

     public string Value { get; set; } 
} 

私が手にエラーが

エラータイプ 「System.Collections.Generic.KeyValuePair`2 [[可能System.String、mscorlib、 バージョン= 4.0の一定の値を作成することができませんでしたです。 0.0、Culture =ニュートラル、 PublicKeyToken = b77a5c561934e089]、[System.String、mscorlib、 バージョン= 4.0.0.0、Culture =ニュートラル、PublicKeyToken = b77a5c561934e089]] '。 この コンテキストでは、プリミティブ型または列挙型のみがサポートされています。

+0

ここの問題はあなたの投稿のコードにありません。他の場所では、クエリが実行される前に 'KeyValuePair 'に変換しています。それを行うコードを見つけて投稿できますか? –

+0

私はそれがC#クエリで見ることができるDictionary "request.SearchFilters"だと思います。私はEFが辞書をIList に変換すると思います。 – NZJames

+0

あなたは変換していません。あなたは 'Any()'で 'f'を使ってkvpを使用しています。 'f.Key'と' f.Value'をローカル変数に保存してから使用してください。 –

答えて

0

クエリのf変数がKeyValuePair<string, string>であるようです。 KVPをSQLに変換することができないので、それらを使用する前にローカル変数として保存する必要があります。

var filters = request.SearchFilters.Select(kvp => new[] { kvp.Key, kvp.Value }).ToArray(); 

var objects = repository.GetObjects().Where(t => 
    filters.All(f => 
     t.ObjectChild.Any(tt => 
      tt.MetaDataPairs.Any(md => 
       md.Key.ToLower() == f[0] && md.Value.ToLower().Contains(f[1]) 
       ) 
      ) 
     ) 
    ).ToList(); 
何を覚えていることはあなたがEFでLINQで行うものは、それがタイプ IQueryable<T>でまだあるときということです

- あなたはToList()を呼び出す前にある、ToArray()ToDictionary()多分AsEnumerable()(私は正直に試したことがありませんAsEnumerable()) - SQLとして表現できる必要があります。これは、DbContextで定義されているSQL型(文字列、整数、ロング、バイト、日付など)とエンティティタイプのみをクエリで使用できることを意味します。他のすべては、それらの形式の1つに分解される必要があります。

EDIT:
ます。また、クエリの反対側から来る試みることができるが、あなたが最初のいくつかのことを必要としています。..

モデル...

[Table("MetaDataPair")] 
public class DbMetaDataPair : IEntityComparable<DbMetaDataPair> 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public long Id { get; set; } 

    [Required] 
    public string Key { get; set; } 

    public string Value { get; set; } 

    // this is the navigation property back up to the ObjectChild 
    public virtual ObjectChild ObjectChild { get;set; } 
} 

public ObjectChild 
{ 
    ... 
    public ICollection<MetaDataPair> MetaDataPairs { get; set; } 

    // this is the navigation property back up to the "Object" 
    public virtual Object Object { get; set; } 
    ... 
} 
クエリの今

...

public IEnumerable<Object> GetObjectsFromRequest(FindObjectRequest request) 
{ 
    foreach(var kvp in request.SearchFilters) 
    { 
     var key = kvp.Key; 
     var value = kvp.Value; 

     yield return metaDataRepository.MetaDataPairs 
      .Where(md => md.Key.ToLower() == key && md.Value.ToLower().Contains(value)) 
      .Select(md => md.ObjectChild.Object) 
    } 
} 

これ番目のSQLクエリの「n」の数を実行する必要があります一致するメタペアの数より良い選択肢は、何らかの形でそれらを結合しようとしていることですが、そのコードを使えば使えないかもしれません。

私はあなたのクラスの名前を本当に知っていないので、私はうまくいくことができました。明らかにObjectはモデルの名前ではありません..

+0

fはIList >であるため、複数あることになります。それが問題だ。 – NZJames

+0

その編集を試してください... –

+0

編集していただきありがとうございます。 {"LINQ式ノード型 'ArrayIndex'はLINQ to Entitiesでサポートされていません。"} – NZJames

関連する問題