Невозможно запросить контекст EF под TPL - PullRequest
2 голосов
/ 20 декабря 2010

У меня есть процесс, в котором я читаю тысячи записей из базы данных, кодирую каждую из них в отдельное сообщение XML и отправляю упомянутое сообщение службе WCF.

На базу данных ссылается модель EF4,Я использую TPL для распараллеливания создания сообщений XML.Проблема возникает с самым первым запросом LINQ:

var practice = (from patient in db.T_AccountHolder
                join practitioner in db.T_Practitioner on patient.DefaultPractitioner_ID equals practitioner.Practitioner_ID
                join _practice in db.T_Practice on practitioner.Practice_ID equals _practice.Practice_ID
                where patient.AccountHolder_ID == accountholder_id
                select _practice).FirstOrDefault();

Я получаю следующее исключение:

ArgumentException: An item with the same key has already been added.

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

Поскольку я использую TPL, яв этой конкретной ситуации.Является ли мое единственное средство НЕ использовать EF?Вернуться к обычным запросам ADO.NET?

Я искал вверх и вниз по этому отличному сайту и Google, но, похоже, не нашел подобного типа вопросов.


РЕДАКТИРОВАТЬ: Вот трассировка стека ошибки.

Exception message: An item with the same key has already been added.

at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Data.Objects.ObjectStateManager.AddStateManagerTypeMetadata(EntitySet entitySet, ObjectTypeMapping mapping)
at System.Data.Objects.ObjectStateManager.GetOrAddStateManagerTypeMetadata(Type entityType, EntitySet entitySet)
at System.Data.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
at System.Data.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__1[TResult](IEnumerable`1 sequence)
at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
at WCFServiceTest.Messages.CreateAccountHolderMessage(Int32 accountholder_id) in C:\Users\Chris\documents\visual studio 2010\Projects\WCFServiceTest\WCFServiceTest\Messages.cs:line 116
at WCFServiceTest.Messages.CreateParallelMessagesForAccountHolder(Int32 accountholder_id, manmayEntities _db, List`1 queue) in C:\Users\Chris\documents\visual studio 2010\Projects\WCFServiceTest\WCFServiceTest\Messages.cs:line 2482
at WCFServiceTest.ParallelWork.<>c__DisplayClass22.<ProcessData_EF>b__1f(Int32 patient_id) in C:\Users\Chris\documents\visual studio 2010\Projects\WCFServiceTest\WCFServiceTest\ParallelWork.cs:line 298

Ответы [ 2 ]

1 голос
/ 21 декабря 2010

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

Это не правильно.Просто один и тот же запрос можно запускать несколько раз.Попробуйте это в тестовом приложении.

Если вы дважды выделите один и тот же объект в контексте, по умолчанию экземпляры будут зафиксированы как один и тот же объект.См. Документы для ObjectQuery.MergeOption.

Вы обычно видите ошибку, которую вы выдаете, когда вы AddObject() дважды используете один и тот же объект.

Я думаю, что ваша ошибка может быть в другом месте.

Кстати, я бы написал ваш запрос следующим образом:

var practice = (from patient in db.T_AccountHolder
                where patient.AccountHolder_ID == accountholder_id
                select patient.Practitioner.Practice).FirstOrDefault();

Хотя это не должно иметь никакого значения для этой проблемы.

0 голосов
/ 25 мая 2016

У меня была та же проблема, после прочтения ответа Кариг пришла идея, что я могу справиться с этим, используя некоторую блокировку ...

это как-то работает, я не уверен сколько, но в прошлый раз яошибка после 3-го или 4-го раза, когда многопоточное приложение вошло в эту часть синхронно, но на этот раз не было примерно 10 раз (отладки теста) (кстати, я больше не сталкивался с этой ошибкой), ...

У меня есть 2 потока, которые синхронно проверяют базу данных на наличие доступных рабочих мест ... затем они ищут работу одновременно, из-за задержки, с которой база данных реагирует, поэтому я думаю, что она выполняет свою работу.

enter image description here

Как вы можете видеть, поток ожидает блокировки, поэтому EF каждый раз обрабатывает только один идентичный запрос и останавливает ошибку ...

лучшим способом будет то, что эти потоки достигнут кешированного списка, через некоторое время вы позволяете потоку запускать другой поток, который заполнит кэш новыми данными, поэтому у вас всегда есть последние данные, и вы не помещаете базу данныхпод прессуверен в получении тех же данных, поэтому блокировка может исчезнуть ... (если вам не нужны точные последние данные)

...