#entity-framework #linq
#entity-framework #linq
Вопрос:
Если я пытаюсь получить детали из машины в список деталей машин из БД, я выполняю это:
Machine ma = new Machine();
ma = dbcontext.Machine.Where(s => s.Guid == guid).ToList()[0];
IQueryable<Part> PartsQuery = from m in db.Machines
where m.Guid == guid
from p in m.Parts
select p;
ma.parts.AddRange(PartsQuery.ToList());
Я получаю в два раза больше деталей в моем списке деталей машины, чем на самом деле в базе данных!
Если я сделаю это вместо последней строки:
List<parts> partsFromDb = PartsQuery.ToList();
ma.parts.AddRange(partsFromDb);
количество частей в списке ma.parts указано правильно. Может кто-нибудь объяснить это мне, пожалуйста?
Ответ №1:
Вы можете добиться того, что пытаетесь сделать, за один переход к вашей базе данных:
Machine mab=context.Machine.Include(m=>m.Parts).FirstOrDefault(m=> m.Guid == guid);
Что касается вашей проблемы, это, вероятно, связано с политикой кэширования EF, и, возможно, также связана с отложенной загрузкой. Я не знаю, как вы тестируете свой код, но если вы выполните следующие действия:
Machine ma = context.Machine.FirstOrDefault(m=> m.Guid == guid);
IQueryable<Part> PartsQuery = from m in db.Machines
where m.Guid == guid
from p in m.Parts
select p;
PartsQuery.ToList(); //materialize your query but don't save the resu<
var parts=ma.parts;// now take a look here and you will see the related parts were loaded
Это должно быть причиной дублирования данных, потому что, когда вы выполняете свой запрос и позже обращаетесь к свойству навигации ( m.parts
), связанные объекты уже есть. Но в любом случае лучший способ получить то, что вам нужно, — это использовать запрос, который я показываю в начале моего ответа.
Ответ №2:
Machine ma = new Machine();
ma = dbcontext.Machine.Where(s => s.Guid == guid).ToList()[0];
IQueryable<Part> PartsQuery = from m in db.Machines
where m.Guid == guid
from p in m.Parts
select p;
ma.parts.AddRange(PartsQuery.ToList());
На 100% эквивалентно:
// 1. Find and retrieve the first machine with the given GUID
Machine machine = dbcontext.Machine.First(s => s.Guid == guid);
// 2. Again, find and retrieve the machines with the given GUID, select the parts of each machine that matches and flatten it down to a single list.
IList<Part> machineParts = db.Machines
.Where(m => m.Guid == guid)
.SelectMany(m => m.Parts)
.ToList();
// 3. Add.. all of the parts to that machine again?
machine.parts.AddRange(machineParts);
Поэтому имеет смысл, что в итоге вы получаете двойные части внутри извлеченной машины.
Честно говоря, я не верю, что последнее изменение, о котором вы говорите, то есть преобразование ‘PartsQuery’ во временную переменную, имеет какое-либо значение в отношении конечного результата вашего machine
.
Там должно происходить что-то еще.
Комментарии:
1. Здравствуйте, почему это: IList<Part> machineParts содержит тот же список, что и этот: machine.parts для вас?
2. И да, он действительно ведет себя именно так, как я его описал. Что я забыл упомянуть, так это то, что я использую поставщика mysql entity framework.
3. извините, я сделал там опечатку. Простите меня, пожалуйста, конечно, я заменил списки. глупый я ^^
4. Ну, единственный сценарий, в котором
machine.parts
с шага 1 может отличатьсяmachineParts
от шага 2, — это если в базе данных есть несколько машин с одинаковым идентификатором GUID (и это звучит ужасно) или если вам удалось загрязнить EntityFramework DbContext двумя машинами с одинаковым идентификатором GUID. Но если вы правильно настроили свой DbContext (с помощью аннотаций свойств или конфигураций EntityType), то это должно быть невозможно.