На работающем проекте MS SQL 2008 R2 + EF + WCF пару раз возникала необъяснимая ситуация.
Все (может и не все, но большая часть точно) выборки через EF начинают кидаться исключениями вроде такого:
System.InvalidOperationException: The specified cast from a materialized 'System.Int32' type to the 'System.String' type is not valid.
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal)
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper.GetColumnValueWithErrorHandling[TColumn](Int32 ordinal)
в lambda_method(Closure , Shaper )
в System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
в System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
в System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
в -- тут пошёл мой код --
или
System.InvalidOperationException: The 'Name' property on 'ххх' could not be set to a 'System.Int32' value. You must set this property to a non-null value of type 'System.String'.
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal)
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper.GetPropertyValueWithErrorHandling[TProperty](Int32 ordinal, String propertyName, String typeName)
в lambda_method(Closure , Shaper )
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
в lambda_method(Closure , Shaper )
в System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
в System.Linq.Buffer`1..ctor(IEnumerable`1 source)
в System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
в -- тут пошёл мой код --
самое первое в логе вот такое
System.IndexOutOfRangeException: Индекс находился вне границ массива.
в System.Data.SqlClient.SqlDataReader.CheckHeaderIsReady(Int32 columnIndex, Boolean permitAsync, String methodName)
в System.Data.SqlClient.SqlDataReader.IsDBNull(Int32 i)
в lambda_method(Closure , Shaper )
в System.Data.Entity.Core.Common.Internal.Materialization.Coordinator.HasNextElement(Shaper shaper)
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.RowNestedResultEnumerator.MaterializeRow()
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.RowNestedResultEnumerator.MoveNext()
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.ObjectQueryNestedEnumerator.TryReadToNextElement()
в System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.ObjectQueryNestedEnumerator.MoveNext()
в System.Linq.Buffer`1..ctor(IEnumerable`1 source)
в System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
в -- тут пошёл мой код --
Перезапуск сайта на IIS не помогает. Если остановить сайт, перезаписать файлы в wwwroot и запустить снова — всё начинает работать как надо.
В общем, по совершенно необъяснимым причинам EF сносит крышу и он становится не способен прочитать что-либо из базы данных.
Что делать? В чём может быть причина? Need help!
EF используется в стиле Code-First. Контекст создаётся один на каждый запрос (NInject InRequestScope).
Версия EF 6.1.30225. Windows Server 2008 R2 (SP1), .NET 4.0, IIS 7.
Здравствуйте, Poul_Ko, Вы писали:
P_K>На вопрос "Кто виноват?" вы ответили. P_K>Но сейчас меня гораздо больше интересует ответы на вопрос "Что делать?"
Здравствуйте, Poul_Ko, Вы писали:
P_K>На вопрос "Кто виноват?" вы ответили. P_K>Но сейчас меня гораздо больше интересует ответы на вопрос "Что делать?"
А я правильно понимаю, что проблема плохо воспроизводится? С виду напоминает косяки с многопоточностью. Может такое быть или у вас всё очень чисто?
Здравствуйте, Nuseraro, Вы писали:
N>Здравствуйте, Poul_Ko, Вы писали:
P_K>>На вопрос "Кто виноват?" вы ответили. P_K>>Но сейчас меня гораздо больше интересует ответы на вопрос "Что делать?"
N>А я правильно понимаю, что проблема плохо воспроизводится? С виду напоминает косяки с многопоточностью. Может такое быть или у вас всё очень чисто?
Верно, не воспроизводится. За две недели работы случилось два раза.
Как-то явно многопоточность не использую, т.е. потоки нигде не создаются, ThreadPool, BeginInvoke, Task и т.п. в серверном коде тоже не применяется.
Про DataContext уже написал — инжектится через NInject, время жизни InRequestScope. По идее использования одного контекста в разных потоках быть не должно.
Хотя вот нашёл один косячок, из-за которого один контекст мог использоваться в одновременно обрабатываемых запросах для выполнения одного мелкого обращения к БД. Странно если такое может влиять на работу остальных экземпляров DataContext.
Здравствуйте, scale_tone, Вы писали:
_>Здравствуйте, Poul_Ko, Вы писали:
P_K>>Что делать? В чём может быть причина? Need help!
_>Вот похожий эксепшен. Там девушка кладет в кэш запрос вместо результата запроса. У Вас ненароком ничего такого не происходит?
Нет, запросы не сохраняю, это точно.
В любом случае спасибо, это наталкивает на мысль проверить не диспозится ли как-то DataContext раньше времени.
System.Data.Entity.Core.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.Data.SqlClient.SqlException: New request is not allowed to start because it should come with valid transaction descriptor.
в System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
в System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
в System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
в System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
в System.Data.SqlClient.SqlDataReader.get_MetaData()
в System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
в System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite)
в System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
в System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
в System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
в System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
в System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
в System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
в System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
--- Конец трассировки внутреннего стека исключений ---
в System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
в System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)
в System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
в System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass3.<GetResults>b__1()
в System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
в System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
в System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
в System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
в System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
в System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
Здравствуйте, Poul_Ko, Вы писали:
P_K>System.Data.Entity.Core.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.Data.SqlClient.SqlException: New request is not allowed to start because it should come with valid transaction descriptor.
Здравствуйте, Poul_Ko, Вы писали:
P_K>EF используется в стиле Code-First. Контекст создаётся один на каждый запрос (NInject InRequestScope).
Скорее всего threading issue и транзакции (TransactionScope).
Если даже контекст инстанцируется как InRequestScope, то могут быть сервисы, в которые ижектится контекст, имеющие большее время жизни.
Также проблема может быть при использовании асинхронности, ибо в .NET 4 асинхронный вызов может быть продолжен в другом потоке, что сносит крышу EF.
Варианты решения:
1) проапгрейдить решение до .NET 4.5
2) задать aspnet:UseTaskFriendlySynchronizationContext="true" (но для этого должен .NET 4.5 стоять) подробнее тут — http://msdn.microsoft.com/en-us/library/hh975440.aspx
Здравствуйте, gandjustas, Вы писали:
G>Также проблема может быть при использовании асинхронности
Всё ещё смешней. SqlClient сам внутри асинхронный. И совершенно тривиальный, и вроде бы синхронный код на тему SqlConnection сотоварищи может вызывать существенно разное поведение в зависимости от фазы Луны. Легко наблюдаемо, например, при пошаговой отладке в сравнении с прямым "прыжком" на breakpoint.
Здравствуйте, drol, Вы писали:
D>Здравствуйте, gandjustas, Вы писали:
G>>Также проблема может быть при использовании асинхронности
D>Всё ещё смешней. SqlClient сам внутри асинхронный. И совершенно тривиальный, и вроде бы синхронный код на тему SqlConnection сотоварищи может вызывать существенно разное поведение в зависимости от фазы Луны. Легко наблюдаемо, например, при пошаговой отладке в сравнении с прямым "прыжком" на breakpoint.
А конкретный пример можно? Так чтобы одна команда в один конекшн и при этом были баги.
Здравствуйте, gandjustas, Вы писали:
G>А конкретный пример можно? Так чтобы одна команда
Можно вообще без команд как таковых. Достаточно Open(), BeginTransaction() и Rollback().
G>в один конекшн и при этом были баги.
Чтобы в один SqlConnection — такого не видел. А хорошо проявляется на распределённых транзакциях. Типа TransactionScope() и внутри несколько вложенных SqlConnection() с BeginTransaction() и Rollback(). При разных таймингах прогонов — пошагово\залпом — на выходе будет разное количество запросов с ROLLBACK. Плюс в пуле останутся "сломанные" SqlConnection'ы:
var connectionStringA = String.Format(@"Data Source={0};Initial Catalog={1};Integrated Security=True;pooling=true;Max Pool Size=20;Enlist=true",
@".\SQLEXPRESS", "DBA");
var connectionStringB = String.Format(@"Data Source={0};Initial Catalog={1};Integrated Security=True;pooling=true;Max Pool Size=20;Enlist=true",
@".\SQLEXPRESS", "DBB");
try
{
using (var transactionScope = new TransactionScope())
{
bool errorOccured;
using (var sqlConnection = new SqlConnection(connectionStringA))
{
sqlConnection.Open();
using (var sqlTransaction = sqlConnection.BeginTransaction())
{
using (var sqlConnection2 = new SqlConnection(connectionStringB))
{
sqlConnection2.Open();
using (var sqlTransaction2 = sqlConnection2.BeginTransaction())
{
using (var sqlConnection3 = new SqlConnection(connectionStringB))
{
sqlConnection3.Open();
using (var sqlTransaction3 = sqlConnection3.BeginTransaction())
{
errorOccured = true;
sqlTransaction3.Rollback();
}
}
if (!errorOccured)
{
sqlTransaction2.Commit();
}
}
}
}
}
if (!errorOccured) { transactionScope.Complete(); }
}
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
for (var i = 0; i < 10; i++)
{
try
{
using (var sqlConnection1 = new SqlConnection(connectionStringB))
{
sqlConnection1.Open();
Debug.WriteLine("Connection successfully open.");
}
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
Здравствуйте, drol, Вы писали:
D>Здравствуйте, gandjustas, Вы писали:
D>Чтобы в один SqlConnection — такого не видел. А хорошо проявляется на распределённых транзакциях. Типа TransactionScope() и внутри несколько вложенных SqlConnection() с BeginTransaction() и Rollback().
А при чем тут асинхронность? В коде случается распределенная транзакция, которая ессесно не дружит с ручными транзакциями.
Здравствуйте, gandjustas, Вы писали:
G>А при чем тут асинхронность?
Я уже об этом говорил. Могу повторить: количество ROLLBACK'ов, которые отправятся на SQL Server, зависит от фазы Луны.
G>В коде случается распределенная транзакция, которая ессесно не дружит с ручными транзакциями.
Сия недружба это отдельный вопрос. Транзакция может быть хоть десять раз распределённой, но приведённый-то код последовательный и синхронный. Сначала Rollback() для sqlTransaction3, потом для sqlTransaction2 (через Dispose() от using'а) и т.д.
Здравствуйте, drol, Вы писали:
D>Распределёнными транзакциями не балуетесь ?
Неа. Пользовался TransactionScope, но он начал требовать DTC, хотя вся работа идёт с одной базой.
Это известный баг, поэтому перешёл на EF-овский механизм context.Database.BeginTransaction().
Здравствуйте, gandjustas, Вы писали:
G>Скорее всего threading issue и транзакции (TransactionScope).
От использования TransactionScope отказались.
G>Если даже контекст инстанцируется как InRequestScope, то могут быть сервисы, в которые ижектится контекст, имеющие большее время жизни.
Да был такой момент, пофиксили, поглядим.
G>Также проблема может быть при использовании асинхронности, ибо в .NET 4 асинхронный вызов может быть продолжен в другом потоке, что сносит крышу EF.
Явной асинхронности тоже нет.
G>ЗЫ. МС снял с поддержки все версии .NET до 4.5.1
Спасибо за ещё один аргумент в пользу проапгрейдить FW на сервере.
Здравствуйте, drol, Вы писали:
D>Здравствуйте, gandjustas, Вы писали:
G>>А при чем тут асинхронность?
D>Я уже об этом говорил. Могу повторить: количество ROLLBACK'ов, которые отправятся на SQL Server, зависит от фазы Луны.
G>>В коде случается распределенная транзакция, которая ессесно не дружит с ручными транзакциями.
D>Сия недружба это отдельный вопрос. Транзакция может быть хоть десять раз распределённой, но приведённый-то код последовательный и синхронный. Сначала Rollback() для sqlTransaction3, потом для sqlTransaction2 (через Dispose() от using'а) и т.д.
Это только кажется. В распределенной транзакции любой rollback локальной транзакции приводит к роллбеку распределенной. Координатор распределенных транзакций создает конкурентность в твоем "какбы последовательном и синхронном коде".
У меня было похожее, когда в запросе использовалось объединение и объединяемые колонки имели разный тип. В зависимости от результата запроса, тип данных был различен(как вариант, где-то написано case when <условие> then 0 else 'ноль' end ). Необходимо явно приводить к определенному типу значения результирующей выборки.
Работоспособность после каких-то манипуляций, возможно, случайна.