новые объекты, добавленные во время длительного цикла

#c# #.net #frameworks #entity

#c# #.net #фреймворки #сущность

Вопрос:

В настоящее время у нас есть производственное приложение, которое работает как служба Windows. Много раз это приложение попадет в цикл, который может занять несколько часов. Мы используем Entity Framework для .net 4.0 для нашего доступа к данным.

Я ищу подтверждение того, что если мы загрузим новые данные в систему после инициализации этого цикла, это не приведет к добавлению элементов в сам цикл. Когда цикл инициализируется, мы ищем данные «по состоянию» на этот момент. Хотя я относительно уверен, что это будет работать точно так же, как использование ADO и выполнение цикла над данными (цикл циклически обрабатывает только данные, которые присутствовали во время инициализации), я ищу подтверждение для коллег.

Заранее спасибо за вашу помощь.

// обновление: вот несколько примеров кода на c # — вопрос тот же, изменится ли перечисление, если в таблицу, которую запрашивает EF, будут добавлены новые элементы?

 IEnumerable<myobject> myobjects = (from o in db.theobjects where o.id==myID select o);
foreach (myobject obj in myobjects)
{
    //perform action on obj here
}
  

Комментарии:

1. Джефф, ты не можешь сказать с уверенностью, это зависит от того, как был написан код, а не от фреймворка. Большинство (не все) программисты пишут пакетные процессы для запроса всех данных в начале процесса. Однако возможно (хотя и маловероятно), что программа запрашивает базу данных на протяжении всей операции. Окончательный ответ требует прохождения кода.

Ответ №1:

Это зависит от вашей точной реализации.

После выполнения запроса к базе данных результаты запроса не изменятся (при условии, что вы не используете отложенную загрузку). Чтобы убедиться в этом, вы можете удалить контекст после получения результатов запроса — это эффективно «перерезает связь» между полученными данными и этой базой данных.

Отложенная загрузка может привести к смешиванию «исходных» и «новых» данных; однако, как только данные будут получены, они станут фиксированным снимком и не будут подвержены обновлениям.

Вы упоминаете, что это длительный процесс; что подразумевает, что может быть задействован очень большой объем данных. Если вы не можете полностью получить все данные, подлежащие обработке (из-за ограничений памяти или других узких мест), то вы, вероятно, не сможете гарантировать, что работаете с исходными данными. Результаты не фиксируются до тех пор, пока не будет выполнен запрос, и любые обновления до выполнения запроса будут отображаться в результатах.

Комментарии:

1. Это был ответ, мне нужно посмотреть, делает ли реализация IEnumerable то же самое, что и выполнение ToList(). Поскольку отложенная загрузка включена по умолчанию в EF

2. Я также нашел подтверждение того, что реализация IEnumerable устраняет отложенную загрузку и загружает результаты в память. Итак, ответ заключается в том, что с кодом, который у меня есть выше, коллекция останется нетронутой.

3. да, как правило IQueryable , это интерфейс, с которым вам нужно быть наиболее осторожным

Ответ №2:

Я думаю, что лучше всего изменить логику вашего приложения таким образом, чтобы, когда логика «цикла» определяла, следует ли ей выполнять другое взаимодействие или выходить, вы воспользовались возможностью загрузить вновь добавленные элементы в список. смотрите псевдокод ниже:

 var repo = new Repository();
while (repo.HasMoreItemsToProcess())
{
   var entity = repo.GetNextItem();
}
  

Дайте мне знать, если это имеет смысл.

Комментарии:

1. Привет, спасибо за это предложение, но меня беспокоит то, что я не хочу, чтобы новые объекты обрабатывались. Ваш код был бы идеальным, если бы мне нужно было проверять наличие новых объектов, а затем вставлять их. Проблема в том, что я не уверен, как Entity Framework работает при циклическом выполнении перечисления. Если он квалифицирует коллекцию в каждом цикле или просто поддерживает коллекцию в том виде, в каком она была изначально инициализирована.

2. понял. он преобразует все, что вы пишете в Linq, в SQL-запрос, поэтому я бы предположил, что каждый раз, когда вы выполняете запрос в контексте, он не «прослушивает» добавление новых строк.

3. (вот почему я предложил добавить свой собственный уровень абстракции за пределами EF)

Ответ №3:

Самый простой способ гарантировать, что это произойдет — если сами данные не слишком большие — это преобразовать данные, которые вы извлекаете из базы данных, в список <> , например, что-то вроде этого (случайно извлеченный из моего текущего проекта):

 var sessionIds = room.Sessions.Select(s => s.SessionId).ToList();
  

А затем выполните итерацию по списку, а не по IEnumerable<> , который в противном случае был бы возвращен. Преобразование его в список запускает перечисление, а затем отправляет все результаты в память.

Если данных слишком много, чтобы поместиться в память, и вам нужно придерживаться IEnumerable<> , то ответ на ваш вопрос зависит от различных настроек базы данных и подключения.

Ответ №4:

Я бы сделал снимок идентификаторов для обработки — быстро и в виде транзакции — а затем обработал этот список так, как вы делаете сегодня.

В дополнение к достижению цели не изменять образец в середине потока, это также дает вам возможность расширить ваше решение для отслеживания состояния каждого элемента по мере его обработки. Для длительно выполняющегося процесса это может быть очень полезно для отчетов о ходе выполнения, перезапуска / повторных попыток и т. Д.