EF сносит крышу
От: Poul_Ko Казахстан  
Дата: 14.11.14 03:51
Оценка: :)
Всем привет.

На работающем проекте 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.
Brainbench transcript #6370594
Re: EF сносит крышу
От: Nuseraro Россия  
Дата: 14.11.14 10:05
Оценка: 4 (1) +3
Если EF мейнстрим, это ещё не значит, что EF — это хорошо
Homo Guglens
Re[2]: EF сносит крышу
От: Poul_Ko Казахстан  
Дата: 14.11.14 10:39
Оценка:
Здравствуйте, Nuseraro, Вы писали:

N>Если EF мейнстрим, это ещё не значит, что EF — это хорошо


На вопрос "Кто виноват?" вы ответили.
Но сейчас меня гораздо больше интересует ответы на вопрос "Что делать?"
Brainbench transcript #6370594
Re[3]: EF сносит крышу
От: DarthSidius  
Дата: 14.11.14 12:18
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>На вопрос "Кто виноват?" вы ответили.

P_K>Но сейчас меня гораздо больше интересует ответы на вопрос "Что делать?"

Похоронить виноватого.
... << RSDN@Home (RF) 1.2.0 alpha 5 rev. 58>>
♠♠♥♠♠♦♥
Re[3]: EF сносит крышу
От: Nuseraro Россия  
Дата: 14.11.14 13:01
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>На вопрос "Кто виноват?" вы ответили.

P_K>Но сейчас меня гораздо больше интересует ответы на вопрос "Что делать?"

А я правильно понимаю, что проблема плохо воспроизводится? С виду напоминает косяки с многопоточностью. Может такое быть или у вас всё очень чисто?
Homo Guglens
Re: EF сносит крышу
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 14.11.14 13:17
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>Что делать? В чём может быть причина? Need help!


Вот похожий эксепшен. Там девушка кладет в кэш запрос вместо результата запроса. У Вас ненароком ничего такого не происходит?
Re[4]: EF сносит крышу
От: Poul_Ko Казахстан  
Дата: 14.11.14 15:28
Оценка:
Здравствуйте, Nuseraro, Вы писали:

N>Здравствуйте, Poul_Ko, Вы писали:


P_K>>На вопрос "Кто виноват?" вы ответили.

P_K>>Но сейчас меня гораздо больше интересует ответы на вопрос "Что делать?"

N>А я правильно понимаю, что проблема плохо воспроизводится? С виду напоминает косяки с многопоточностью. Может такое быть или у вас всё очень чисто?


Верно, не воспроизводится. За две недели работы случилось два раза.
Как-то явно многопоточность не использую, т.е. потоки нигде не создаются, ThreadPool, BeginInvoke, Task и т.п. в серверном коде тоже не применяется.
Про DataContext уже написал — инжектится через NInject, время жизни InRequestScope. По идее использования одного контекста в разных потоках быть не должно.
Хотя вот нашёл один косячок, из-за которого один контекст мог использоваться в одновременно обрабатываемых запросах для выполнения одного мелкого обращения к БД. Странно если такое может влиять на работу остальных экземпляров DataContext.
Brainbench transcript #6370594
Re[2]: EF сносит крышу
От: Poul_Ko Казахстан  
Дата: 14.11.14 15:32
Оценка:
Здравствуйте, scale_tone, Вы писали:

_>Здравствуйте, Poul_Ko, Вы писали:


P_K>>Что делать? В чём может быть причина? Need help!


_>Вот похожий эксепшен. Там девушка кладет в кэш запрос вместо результата запроса. У Вас ненароком ничего такого не происходит?


Нет, запросы не сохраняю, это точно.
В любом случае спасибо, это наталкивает на мысль проверить не диспозится ли как-то DataContext раньше времени.
Brainbench transcript #6370594
Re: EF сносит крышу
От: Poul_Ko Казахстан  
Дата: 14.11.14 15:36
Оценка:
Ещё из лога:

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)

Что бы это могло значить?
Brainbench transcript #6370594
Re[2]: EF сносит крышу
От: drol  
Дата: 14.11.14 20:34
Оценка:
Здравствуйте, 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.


Распределёнными транзакциями не балуетесь ?
Re: EF сносит крышу
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 15.11.14 01:23
Оценка:
Здравствуйте, 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

ЗЫ. МС снял с поддержки все версии .NET до 4.5.1
Re[2]: EF сносит крышу
От: drol  
Дата: 15.11.14 02:10
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Также проблема может быть при использовании асинхронности


Всё ещё смешней. SqlClient сам внутри асинхронный. И совершенно тривиальный, и вроде бы синхронный код на тему SqlConnection сотоварищи может вызывать существенно разное поведение в зависимости от фазы Луны. Легко наблюдаемо, например, при пошаговой отладке в сравнении с прямым "прыжком" на breakpoint.
Re[3]: EF сносит крышу
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 15.11.14 02:24
Оценка:
Здравствуйте, drol, Вы писали:

D>Здравствуйте, gandjustas, Вы писали:


G>>Также проблема может быть при использовании асинхронности


D>Всё ещё смешней. SqlClient сам внутри асинхронный. И совершенно тривиальный, и вроде бы синхронный код на тему SqlConnection сотоварищи может вызывать существенно разное поведение в зависимости от фазы Луны. Легко наблюдаемо, например, при пошаговой отладке в сравнении с прямым "прыжком" на breakpoint.


А конкретный пример можно? Так чтобы одна команда в один конекшн и при этом были баги.
Re[4]: EF сносит крышу
От: drol  
Дата: 15.11.14 02:58
Оценка:
Здравствуйте, 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);
                }
            }
Re[5]: EF сносит крышу
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 15.11.14 10:01
Оценка:
Здравствуйте, drol, Вы писали:

D>Здравствуйте, gandjustas, Вы писали:



D>Чтобы в один SqlConnection — такого не видел. А хорошо проявляется на распределённых транзакциях. Типа TransactionScope() и внутри несколько вложенных SqlConnection() с BeginTransaction() и Rollback().


А при чем тут асинхронность? В коде случается распределенная транзакция, которая ессесно не дружит с ручными транзакциями.
Re[6]: EF сносит крышу
От: drol  
Дата: 15.11.14 11:22
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>А при чем тут асинхронность?


Я уже об этом говорил. Могу повторить: количество ROLLBACK'ов, которые отправятся на SQL Server, зависит от фазы Луны.

G>В коде случается распределенная транзакция, которая ессесно не дружит с ручными транзакциями.


Сия недружба это отдельный вопрос. Транзакция может быть хоть десять раз распределённой, но приведённый-то код последовательный и синхронный. Сначала Rollback() для sqlTransaction3, потом для sqlTransaction2 (через Dispose() от using'а) и т.д.
Re[3]: EF сносит крышу
От: Poul_Ko Казахстан  
Дата: 15.11.14 14:36
Оценка:
Здравствуйте, drol, Вы писали:

D>Распределёнными транзакциями не балуетесь ?


Неа. Пользовался TransactionScope, но он начал требовать DTC, хотя вся работа идёт с одной базой.
Это известный баг, поэтому перешёл на EF-овский механизм context.Database.BeginTransaction().
Brainbench transcript #6370594
Re[2]: EF сносит крышу
От: Poul_Ko Казахстан  
Дата: 15.11.14 14:42
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Скорее всего threading issue и транзакции (TransactionScope).

От использования TransactionScope отказались.

G>Если даже контекст инстанцируется как InRequestScope, то могут быть сервисы, в которые ижектится контекст, имеющие большее время жизни.

Да был такой момент, пофиксили, поглядим.

G>Также проблема может быть при использовании асинхронности, ибо в .NET 4 асинхронный вызов может быть продолжен в другом потоке, что сносит крышу EF.

Явной асинхронности тоже нет.

G>ЗЫ. МС снял с поддержки все версии .NET до 4.5.1

Спасибо за ещё один аргумент в пользу проапгрейдить FW на сервере.
Brainbench transcript #6370594
Re[7]: EF сносит крышу
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 15.11.14 17:29
Оценка:
Здравствуйте, drol, Вы писали:

D>Здравствуйте, gandjustas, Вы писали:


G>>А при чем тут асинхронность?


D>Я уже об этом говорил. Могу повторить: количество ROLLBACK'ов, которые отправятся на SQL Server, зависит от фазы Луны.


G>>В коде случается распределенная транзакция, которая ессесно не дружит с ручными транзакциями.


D>Сия недружба это отдельный вопрос. Транзакция может быть хоть десять раз распределённой, но приведённый-то код последовательный и синхронный. Сначала Rollback() для sqlTransaction3, потом для sqlTransaction2 (через Dispose() от using'а) и т.д.


Это только кажется. В распределенной транзакции любой rollback локальной транзакции приводит к роллбеку распределенной. Координатор распределенных транзакций создает конкурентность в твоем "какбы последовательном и синхронном коде".
Re: EF сносит крышу
От: namespace  
Дата: 15.11.14 17:40
Оценка:
У меня было похожее, когда в запросе использовалось объединение и объединяемые колонки имели разный тип. В зависимости от результата запроса, тип данных был различен(как вариант, где-то написано case when <условие> then 0 else 'ноль' end ). Необходимо явно приводить к определенному типу значения результирующей выборки.

Работоспособность после каких-то манипуляций, возможно, случайна.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.