Вы забыли сообщить нам, какие объекты находятся в вашей коллекции items
.Я думаю, что они Listings
.Ваш случай не работает, потому что itemsTemp
- это набор Categories
, а каждый item1
- это Category
, что, конечно, не может быть приведено к Listing
.
.
Совет: для устранения проблем с кастингом замените слово var
на тип, который вы на самом деле ожидаете.Компилятор предупредит вас о неверных типах.Также используйте правильные идентификаторы в ваших лямбда-выражениях.Это облегчает их чтение
IQueryable<???> items = ... // collection of Listings?
List<Listing> itemsSelected = null;
IQueryable<Category> enabledCategories = model.Categories.Where(category => category.Enabled));
foreach (Category category in enabledCategories)
{
IEnumerable<Category> itemsTemp = items
.Select(item => item.Categories
.Where(tmpCategory => tmpCategory.ID == category.ID));
foreach (Category item1 in itemsTemp)
{
// can't cast a Category to a Listing
Мы вернёмся к этому коду позже.
Если я посмотрю на ваш SQL, то вам понадобится следующее:
У меня есть DbContext
с (как минимум) Listings
и Categories
.Я хочу, чтобы все Listings
с их Categories
, которые имели Id категории 1 или 3
Приятно видеть, что вы следовали соглашениям о коде в начале структуры лица , однако вызабыл объявить ваши коллекции virtual :
В каркасе сущностей столбцы в таблице представлены не виртуальными свойствами.Виртуальные свойства представляют отношения между таблицей.
С небольшим изменением ваше отношение «многие ко многим» может быть автоматически определено структурой сущностей.Обратите внимание на virtual
перед ICollection
class Listing
{
public int ID { get; set; }
// every Listing has zero or more categories (many-to-many)
public virtual ICollection<Category> Categories { get; set; }
...
}
class Category
{
public int ID { get; set; }
// every Category is used by zero or more Listings (many-to-many)
public ICollection<Listing> Listings { get; set; }
...
public bool Enabled {get; set;}
}
И DbContext
public MyDbContext : DbContext
{
public DbSet<Listing> Listings {get; set;}
public DbSet<Category> Categories {get; set;}
}
Хотя реляционная база данных реализует отношение «многие ко многим» с таблицей соединений,вам не нужно указывать это в своем DbContext
.Entity Framework обнаруживает, что вы хотите спроектировать «многие ко многим», и создает для вас соединительную таблицу.
Но как я могу выполнить свои объединения без доступа к соединительной таблице?
Ответ: Не делайте объединений, используйте ICollections
!
Entity Framework знает, какие внутренние объединения необходимы, и будет выполнять объединения для вас.
Вернуться к вашему SQLкод:
Дайте мне все (или некоторые) свойства всех Listings
, у которых есть хотя бы один Category
с Id, равным 1 или 3
var result = myDbcontext.Listings
.Select(listing => new
{ // select only the properties you plan to use
Id = listing.Id,
Name = listing.Name,
...
Categories = listing.Categories
// you don't want all categories, you only want categories with id 1 or 3
.Where(category => category.Id == 1 || category.Id == 3)
.Select(category => new
{
// again select only the properties you plan to use
Id = category.Id,
Enabled = category.Enabled,
...
})
.ToList(),
})
// this will also give you the Listings without such Categories,
// you only want Listings that have any Categories left
.Where(listing => listing.Categories.Any());
Одна из более медленных частей запросов к базе данных - передача выбранных данных из СУБД в локальный процесс.Следовательно, целесообразно передавать только те свойства, которые вы действительно планируете использовать.Например, вам не понадобятся внешние ключи отношений «один ко многим», вы знаете, что они равны значению Id части one
в «один ко многим».
Назадна ваш код
Мне кажется, что ваши items
равны Listings
.В этом случае ваш код хочет, чтобы все Listings
имели хотя бы один включенный Category
var result = myDbContext.Listings
.Where(listing => ...) // only if you don't want all listings
.Select(listing => new
{
Id = listing.Id,
Name = list.Name,
Categories = listing.Categories
.Where(category => category.Enabled) // keep only the enabled categories
.Select(category => new
{
Id = category.Id,
Name = category.Name,
...
})
.ToList(),
})
// this will give you also the Listings that have only disabled categories,
// so listings that have any categories left. If you don't want them:
.Where(listing => listing.Categories.Any());