Периодическое InvalidCastException и "Сервер не смог возобновить транзакцию" с Linq
Я вижу это на нашей сценической системе, после того, как она была в течение 2-3 дней.
"Сервер не смог возобновить транзакцию. Desc: 39000000ef." (с desc: xxx увеличивается каждый раз).
Трассировка стека показывает
System.Data.SqlClient.SqlException: The server failed to resume the transaction. Desc:39000000ef.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader()
at System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult)
at System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at ...
После того, как это произошло, весь сервер идет к черту. Похоже, что метаданные уже не правильно представлены в памяти, потому что впоследствии я вижу много InvalidCastExceptions. Я предполагаю, что это связано с тем, что система пытается десериализовать строку в поле int, потому что метаданные неправильно смещены.
то есть.
System.InvalidCastException: Specified cast is not valid.
at System.Data.SqlClient.SqlBuffer.get_Int32()
at System.Data.SqlClient.SqlDataReader.GetInt32(Int32 i)
at Read_Order(ObjectMaterializer`1 )
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
Что это значит?
Я уверен, что база данных не была обновлена позади систем, и база данных была в сети все время.
Проблема сохраняется здесь, пока сервер не перезагрузится, после чего все будет хорошо работать.
Нужно ли иметь код, который заново устанавливает соединение с базой данных, если он не работает? Разве каркас не обрабатывает это сам?
Я использую сервер Sql 2008, IIS 6 и .Net 3.5SP1
UPDATE:
Структура кода делает что-то вроде этого:
var dc = new datacontext()
IList<someobject> objs = dc.GetAllItemsToProcess()
var dc2 = new datacontext();
foreach( var o in objs ) {
try {
var o2 = dc2.someobjects.SingleOrDefault(x=>x.id = o.id);
// do stuff to o2
dc2.save();
} catch() {
// something failed so restart datacontext()
dc2 = new datacontext();
}
}
Ответы
Ответ 1
Просто обновление:
- Я отследил ошибку в использовании Linq2Sql-объектов, переданных в качестве источников данных непосредственно в Report Server.
т.е. мы делали что-то вроде этого:
List<Order> orderList = orderRepository.getOrders();
ReportViewer rv = new ReportViewer();
rv.LocalReport.DataSources.Add("OrderList", orderList);
rv.Render();
По какой-то причине это привело к тому, что datacontext запутался даже при работе в одном домене приложений.
Ответ 2
Вероятно, это не проблема с вашим кодом. Это ошибка в SQL Server. У них была аналогичная проблема в SQL Server 2005. Это произошло только в условиях, которые были в порядке, так что очень немногие люди когда-либо видели это, а те, которые были очень запутаны.
Сказав это, вот некоторые вещи, чтобы проверить, что работали для других с той же проблемой:
- Ищите DataReaders, которые не являются
закрыто. Убедитесь, что вы делаете
myReader.Close() после того, как вы прочитали
строки, которые вы хотите. Многие люди просто рок
без закрытия.
- Использовать собственный класс SqlTransaction
вместо OleDbTransactions везде
возможно.
- Посмотрите на свои транзакции. Убедиться
вы совершаете/откатываете назад
перед тем, как закрыть свое соединение.
- Используйте Connection.BeginTransation скорее
чем Connection.BeginDbTransaction
Ответ 3
- Не используйте один и тот же DataContext для разных операций. Используйте тот же DataContext для группировки набора операций, которые вы будете отправлять. Если у вас есть другой набор, который вы будете отправлять отдельно, используйте отдельный DataContext.
- Я не уверен, но также проверяю, перечисляете ли вы более двух IQueryables одновременно. В этом случае попробуйте использовать отдельный DataContext для второго перечисления, чтобы убедиться, что он не вызван тем, что linq2sql пытается открыть для читателей в то же время.
- Убедитесь, что ваша модель обновлена с вашей БД. Структура, определяемая дизайнером Linq2sql, не обновляется автоматически, поэтому при добавлении поля вам нужно убедиться, что он добавлен в конструктор (возможно, путем повторного добавления таблицы, если вы не переименовали какие-либо поля).
Ответ 4
Используете ли вы объект DataContext для атомных единиц работы? это поможет много проблем с подключением, если они существуют.
также иногда вам нужно проверить физический урон в ОЗУ, например.