C # Entity-Framework: Как я могу объединить .Find и .Include для модельного объекта?

95

Я занимаюсь учебным курсом mvcmusicstore. Я заметил что-то при создании эшафота для менеджера альбомов (добавьте удаление).

Я хочу написать код элегантно, поэтому я ищу чистый способ написать это.

FYI я делаю магазин более общим:

Альбомы = Элементы

Жанры = Категории

Исполнитель = Бренд

Вот как извлекается индекс (сгенерированный MVC):

var items = db.Items.Include(i => i.Category).Include(i => i.Brand);

Вот как извлекается элемент для удаления:

Item item = db.Items.Find(id);

Первый возвращает все элементы и заполняет модели категорий и брендов внутри модели элементов. Второй, не заполняет категорию и бренд.

Как я могу написать второй для поиска и заполнить внутри (желательно в 1 строке)... теоретически - что-то вроде:

Item item = db.Items.Find(id).Include(i => i.Category).Include(i => i.Brand);
  • 0
    Если кому-то нужно сделать это в основном в .net-core, посмотрите мой ответ
Теги:
entity-framework
asp.net-mvc

3 ответа

101
Лучший ответ

Сначала вам нужно использовать Include(), а затем извлечь один объект из результирующего запроса:

Item item = db.Items
              .Include(i => i.Category)
              .Include(i => i.Brand)
              .SingleOrDefault(x => x.ItemId == id);
  • 0
    Я пытался возиться с заказом раньше ... но безуспешно. Вот ошибка, которую я получаю с вашим кодом: «System.Linq.IQueryable <LiquorStore.Models.Item>» не содержит определения для «Найти» и не имеет метода расширения «Найти», принимающего первый аргумент типа «System.Linq. IQueryable <LiquorStore.Models.Item> 'может быть найден (вам не хватает директивы using или ссылки на сборку?)
  • 2
    Попробуйте ...ToList().Find(id) или ...SingleOrDefault() вместо этого. Смотрите модифицированный ответ.
Показать ещё 8 комментариев
44

Ответ Dennis использует Include и SingleOrDefault. Последний отправляется в базу данных.

Альтернативой является использование Find в сочетании с Load для явной загрузки связанных объектов...

Ниже примера MSDN:

using (var context = new BloggingContext()) 
{ 
  var post = context.Posts.Find(2); 

  // Load the blog related to a given post 
  context.Entry(post).Reference(p => p.Blog).Load(); 

  // Load the blog related to a given post using a string  
  context.Entry(post).Reference("Blog").Load(); 

  var blog = context.Blogs.Find(1); 

  // Load the posts related to a given blog 
  context.Entry(blog).Collection(p => p.Posts).Load(); 

  // Load the posts related to a given blog  
  // using a string to specify the relationship 
  context.Entry(blog).Collection("Posts").Load(); 
}

Конечно, Find немедленно возвращается без запроса в хранилище, если этот объект уже загружен контекстом.

  • 23
    Этот метод использует Find поэтому, если сущность присутствует, для самой сущности нет обхода в DB. НО, у вас будет туда-обратно для каждого отношения вы находитесь Load ING, в то время как SingleOrDefault комбинация с Include нагрузок все в один присест.
  • 0
    Когда я сравнил 2 в профилировщике SQL, Find / Load был лучше для моего случая (у меня было соотношение 1: 1). @Iravanchi: ты хочешь сказать, что если бы я имел отношение 1: m, он бы назвал m раз магазином? ... потому что это не имело бы большого смысла.
Показать ещё 5 комментариев
0

Не работает для меня. Но я решил это, сделав вот так.

var item = db.Items
             .Include(i => i.Category)
             .Include(i => i.Brand)
             .Where(x => x.ItemId == id)
             .First();

Не знаю, хорошо ли это решение. Но другой, которого дал Деннис, дал мне ошибку bool в .SingleOrDefault(x => x.ItemId = id);

  • 3
    Решение Дениса тоже должно сработать. Возможно, у вас есть эта ошибка в SingleOrDefault(x => x.ItemId = id) только из-за неправильного одиночного = вместо двойного == ?
  • 5
    да, похоже, что вы использовали = не ==. Синтаксическая ошибка;)
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню