2016-04-06 4 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 знает, как его перевести.

Update (Фактическое Fix)

Фактическое разрешение к проблеме включает удаление использование фактического сбора лиц, используемых в рамках вызова 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

Спасибо за ваш ответ. Я пробовал сравнивать по id города (как показано в обновленном коде в моем ответе), но я все равно получаю такое же исключение. –

+0

Иногда это может помочь фактически взять коллекцию, с которой вы сравниваете, и поместить ее в память: 'var cities = f.Cities.Select (c => c.ZipCode.City.Id) .ToArray();' и затем использовать что в вашем последующем запросе: 'realestates = realestates.Where (x => cities.Any (c => c == x.Id);' –

+0

Это трюк! Хранение идентификатора города города как списка, а не только сами города как список сделали запрос завершенным успешно. Мне кажется странным, что это необходимо. В любом случае, большое спасибо за вашу помощь! –

Смежные вопросы