2016-04-06 19 views
0

私はテーブルをフィルタリングし、フィルタに一致する行を返すメソッドがあります。 はここに方法だ:私は次の例外を取得するメソッドを呼び出すたびLinqクエリを実行すると例外が発生する

しかし
public List<RealEstate> GetMatchingRealestatesQuery(RealestateFilter f, RealestateSiteDbContext context) 
    { 
     IQueryable<RealEstate> realestates = context.RealEstates.Where(x => x.Status == RealEstateStatus.Open); 
     realestates = realestates.Where(x => f.Cities.Any(y => x.ZipCode.City.Id == y.Id)); 
     if (f.MaxRent > 0) 
      realestates = realestates.Where(x => x.Rent <= f.MaxRent); 
     if (f.MinArea > 0) 
      realestates = realestates.Where(x => x.Area >= f.MinArea); 
     if (f.MinRooms > 0) 
      realestates = realestates.Where(x => x.Rooms <= f.MinRooms); 
     realestates = realestates.Where(x => f.RealestateTypes.Has(x.Type)); 
     realestates = realestates.Where(x => f.RentalPeriod.Has(x.RentalPeriod)); 

     return realestates.ToList(); 
    } 

、:

型「RealestateSiteModel.City」が一定の値を作成することができません。 この コンテキストでは、プリミティブ型または列挙型のみがサポートされています。

IQueryableを構築してから、.ToListを呼び出してクエリを実行するだけです。この例外の原因は何ですか?

答えて

1

ここでの問題は、LINQが複雑なオブジェクト/クラスをSQLコードに変換する方法を知らないことです。あなたが呼び出しをフィルタリングしようとすると、メモリ内のオブジェクトとそれらを比較しようとしている場合

一般的に、あなたは(たとえば、プリミティブ型のコレクションのみを使用)LINQは、それらを処理する方法を知っていることを確認する必要があります:

それができない場合
public List<RealEstate> GetMatchingRealestatesQuery(RealestateFilter f, RealestateSiteDbContext context) 
{ 
    // This works just fine as status is going to be a boolean 
    var realestates = context.RealEstates.Where(x => x.Status == RealEstateStatus.Open); 
    // Here's where things get tricky as LINQ doesn't know what City is 
    // Is there some ID that you could use that might make this easier, 
    // such as x.ZipCode.City.CityId or something? 
    realestates = realestates.Where(x => f.Cities.Any(y => x.ZipCode.City == y)); 

    // Other code omitted for brevity 

    return realestates.ToList(); 
} 

は、その後、通常のクエリのこれらの種類は、ほとんど遅延実行を活用するために取得しないと、多くの場合、あなたはToList()コールを介してメモリに、メモリ内の全コレクションを格納し、フィルタリングする必要が:

public List<RealEstate> GetMatchingRealestatesQuery(RealestateFilter f, RealestateSiteDbContext context) 
{ 
    // This will wipe out any deferred execution and perform the 
    // rest of your operations in-memory 
    var realestates = context.RealEstates.Where(x => x.Status == RealEstateStatus.Open).ToList(); 

    // Other code omitted for brevity 

    return realestates; 
} 

このアプローチは、必要以上に多くのデータを取り戻すのではなく、照会しているものを正確に再構成して、LINQがそれをどのように翻訳するかを知る必要があることを避けるためには理想的ではありません。

更新(実際の修)問題への実際の解像度は、次の行にlamdba呼び出し内で使用されているエンティティの実際のコレクションの使用を取り除く関与

realestates = realestates.Where(x => f.Cities.Any(y => x.ZipCode.City.Id == y.Id)); 

LINQはCitiesコレクションのプロパティを変換して評価する方法を知らないので、これは爆発します。ただし、プリミティブ型として、メモリ内に、照会されているオブジェクトのコレクションを保存することができますし、その後、使用することができる必要があります:あなたの答えのための

var cities = f.Cities.Select(c => c.ZipCode.City.Id).ToArray(); 
realestates = realestates.Where(x => cities.Any(c => c == x.Id); 
+0

感謝。 City ID(私の答えの更新されたコードに示されている)と比較しようとしましたが、私はまだ非常に同じ例外を受け取ります。 –

+0

これは時には、比較しているコレクションを実際にメモリに取り込むのに役立ちます: 'var cities = f.Cities.Select(c => c.ZipCode.City.Id).ToArray();'あなたの後続のクエリでは: 'realestates = realestates.Where(x => cities.Any(c => c == x.Id);) –

+0

それはトリックでした! 私はそれをすることが必要であることを奇妙に感じます。 とにかく、ありがとうございました! –

関連する問題