Invalid attempt of read when the reader is closed
От: Naf2000  
Дата: 23.02.21 16:02
Оценка:
При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?
Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?
Вот элементарный код:
            using (var db = new TestDB())
            {
                db.BeginTransaction();
                foreach (var st in db.Entinies.Select(_ => _.UID))
                {
                    db.Items.Update(x => false, x => x);
                }
                db.CommitTransaction();
            }

Вот ошибка:

System.InvalidOperationException
HResult=0x80131509
Сообщение = Invalid attempt of read when the reader is closed.
Источник = FirebirdSql.Data.FirebirdClient
Трассировка стека:
at FirebirdSql.Data.FirebirdClient.FbDataReader.CheckState()
at FirebirdSql.Data.FirebirdClient.FbDataReader.Read()
at LinqToDB.Linq.QueryRunner.<ExecuteQuery>d__12`1.MoveNext()
at ConsoleApp11.Program.Main(String[] args) in C:\Users\User\source\repos\ConsoleApp11\ConsoleApp11\Program.cs:line 51

linq2db
Re: Invalid attempt of read when the reader is closed
От: Слава  
Дата: 23.02.21 17:54
Оценка:
Здравствуйте, Naf2000, Вы писали:

N>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

Может у вас автокоммит включен? Да и само обновление в цикле как-то эммм...
Re[2]: Invalid attempt of read when the reader is closed
От: Naf2000  
Дата: 23.02.21 18:05
Оценка:
Здравствуйте, Слава, Вы писали:

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


N>>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

С>Может у вас автокоммит включен? Да и само обновление в цикле как-то эммм...


Где управляется? у меня же явно указано начало и фиксации транзакции
Про обновление в цикле — я просто разные сценарии тестирую. Подойдет ли мне фреймворк в целом.
Re: Invalid attempt of read when the reader is closed
От: varenikAA  
Дата: 24.02.21 06:03
Оценка:
Здравствуйте, Naf2000, Вы писали:

N> почему чтение закрывается после первого же Update?

не факт, возможно update в кишках тоже читает т.к. идет обращение к другой таблице (items), падаем именно на итеррации?
и, да, ваш код отнюдь не прост
N> Или надо материализовать результат чтения?
думаю да, ToList() в самый раз.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Отредактировано 24.02.2021 6:10 Разраб . Предыдущая версия .
Re: Invalid attempt of read when the reader is closed
От: Danchik Украина  
Дата: 24.02.21 07:07
Оценка:
Здравствуйте, Naf2000, Вы писали:

N>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

Надо материализовать через ToList()

Я надеюсь это не рабочий код? Мы ж..у рвем чтобы у вас была возможность работать эффективно с базой, а тут цикл с апдейтами.
Re: Invalid attempt of read when the reader is closed
От: fmiracle  
Дата: 24.02.21 11:39
Оценка:
Здравствуйте, Naf2000, Вы писали:

N>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

Почему закрывается непонятно, но в целом из одного соединения нельзя одновременно и читать данные и DataReader и выполнять другие операции. Надо сперва дочитать до конца чтение (.ToList()), а потом уже выполнять изменения. То же самое будет и при ручной работе в ADO.NET без linq2db.
Re[2]: Invalid attempt of read when the reader is closed
От: Jack128  
Дата: 24.02.21 11:54
Оценка: -1
Здравствуйте, Danchik, Вы писали:

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


N>>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

D>Надо материализовать через ToList()

А зачем ?? Ну то есть — это ж искусственное ограничение, которые linq2db зачем то навязывает клиентам
Re[2]: Invalid attempt of read when the reader is closed
От: Jack128  
Дата: 24.02.21 11:58
Оценка: -1
Здравствуйте, fmiracle, Вы писали:

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


N>>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

F>Почему закрывается непонятно, но в целом из одного соединения нельзя одновременно и читать данные и DataReader и выполнять другие операции. Надо сперва дочитать до конца чтение (.ToList()), а потом уже выполнять изменения. То же самое будет и при ручной работе в ADO.NET без linq2db.


Это какое ограничение MSSQL? Потому что на уровне интерфейса DbConnection ничего такого нет. Ну по крайней мере я ничего такого не вижу.
Re[3]: Invalid attempt of read when the reader is closed
От: fmiracle  
Дата: 24.02.21 12:29
Оценка:
Здравствуйте, Jack128, Вы писали:

F>>Почему закрывается непонятно, но в целом из одного соединения нельзя одновременно и читать данные и DataReader и выполнять другие операции. Надо сперва дочитать до конца чтение (.ToList()), а потом уже выполнять изменения. То же самое будет и при ручной работе в ADO.NET без linq2db.

J>Это какое ограничение MSSQL? Потому что на уровне интерфейса DbConnection ничего такого нет. Ну по крайней мере я ничего такого не вижу.

В интерфейсе и не увидишь. В общем случае в теории такого ограничения может и не быть, но на практике в mssql оно есть, оракл и постре, насколько я помню — тоже. Проявляется оно исключением вида "There is already opened datareader" или как-то так оно звучало.
Можно решить включением MultipleActiveResultSets в настройках, но это, емнип, по сути открывает несколько соединения неявным образом.

P.S.
Вспомнив про MultipleActiveResultSets подумал, что может быть и я и не прав и ограничение только на два открытых читателя из БД через одно соединение. Возможно так, да.
Re[3]: Invalid attempt of read when the reader is closed
От: Danchik Украина  
Дата: 24.02.21 12:36
Оценка:
Здравствуйте, Jack128, Вы писали:

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


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


N>>>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>>>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

D>>Надо материализовать через ToList()

J>А зачем ?? Ну то есть — это ж искусственное ограничение, которые linq2db зачем то навязывает клиентам

Охренеть. Мы держим открытым reader чтобы не материализировать все обьекты сразу, а тут предъявляют претензии.
Re[4]: Invalid attempt of read when the reader is closed
От: Jack128  
Дата: 24.02.21 14:15
Оценка:
Здравствуйте, Danchik, Вы писали:

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


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


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


N>>>>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>>>>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

D>>>Надо материализовать через ToList()

J>>А зачем ?? Ну то есть — это ж искусственное ограничение, которые linq2db зачем то навязывает клиентам

D>Охренеть. Мы держим открытым reader чтобы не материализировать все обьекты сразу, а тут предъявляют претензии.


Да нет, претензии в том, что вы закрываете ридер, как только пошел другой запрос через тоже соединение. На голом ADO.NET всё работает как надо

public void SampleSelectTest([IncludeDataSources(false, ProviderName.Firebird)] string context)
        {
            using (var db = (DataConnection)GetDataContext(context))
            {
                var connection = db.Connection;
                using var transaction = connection.BeginTransaction();                
                var selectCommand = connection.CreateCommand();
                selectCommand.Transaction = transaction;
                selectCommand.CommandText = @"
select ""PersonID""
from ""Person""
";
                using var reader = selectCommand.ExecuteReader();
                
                while(reader.Read())
                {
                    using var updateCommand = connection.CreateCommand();
                    updateCommand.Transaction = transaction;
                    updateCommand.CommandText = string.Format(@"update ""Person"" set ""FirstName"" = 'cfewfwe' where ""PersonID"" = {0}", reader.GetInt32(0));
                    updateCommand.ExecuteNonQuery();                    
                }

                transaction.Rollback();
            }
        }
Отредактировано 24.02.2021 14:18 Jack128 . Предыдущая версия .
Re[5]: Invalid attempt of read when the reader is closed
От: Danchik Украина  
Дата: 24.02.21 16:58
Оценка:
Здравствуйте, Jack128, Вы писали:

[Skip]

https://github.com/linq2db/linq2db/pull/2728
Re[3]: Invalid attempt of read when the reader is closed
От: Danchik Украина  
Дата: 24.02.21 17:01
Оценка:
Здравствуйте, Naf2000, Вы писали:

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


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


N>>>При изучении linq2db столкнулся с непониманием, почему чтение закрывается после первого же Update?

N>>>Нельзя одновременно читать и писать? А как это делать в одно транзакции? Или надо материализовать результат чтения?

С>>Может у вас автокоммит включен? Да и само обновление в цикле как-то эммм...


N>Где управляется? у меня же явно указано начало и фиксации транзакции

N>Про обновление в цикле — я просто разные сценарии тестирую. Подойдет ли мне фреймворк в целом.

По идее ваш случай должен будет работать после этого фикса. Но пока придется подождать
https://github.com/linq2db/linq2db/pull/2728
Re[5]: Invalid attempt of read when the reader is closed
От: IT Россия linq2db.com
Дата: 24.02.21 18:53
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Да нет, претензии в том, что вы закрываете ридер, как только пошел другой запрос через тоже соединение. На голом ADO.NET всё работает как надо


В этом примере используется два объекта SqlCommand, поэтому и работает. В linq2db DataConnection работает с одной командой. Можно создать два DataConnection, один для чтения, другой для записи и всё должно заработать.
Если нам не помогут, то мы тоже никого не пощадим.
Re: Invalid attempt of read when the reader is closed
От: Mace Windu  
Дата: 25.02.21 10:53
Оценка: 133 (2) +1
Здравствуйте, Naf2000, Вы писали:

Вощем-то уже ответили, почему такое происходит сейчас, но просуммирую в одном сообщении для ясности.

На данный момент в linq2db DataConnection работает с одним инстансом DbCommand.

В данном случае у нас выполняется две SQL комманды — сначала открывается DbDataReader и потом на том же инстансе DbCommand при активном ридере выполняется вторая команда для обновления.
Так как ADO.NET такие сценарии не оговаривает, провайдеры тут ведут себя кто как хочет, но в целом большинство из них не позволяет переиспользовать команду если у неё есть активный ридер. В данном случае например провайдер закрывает ридер когда мы делаем update.

Для этой проблемы я запилил https://github.com/linq2db/linq2db/pull/2728, который такие моменты будет корректно обрабатывать, оставляя в покое инстанс команды с активным ридером, но так как это довольно серьезное изменение, мерж отложен до следующей мажорной версии (4.0).

Вообще мы планируем параллельно выпускать превью 4-ки для таких фич (скорее всего первый пойдет параллельно с 3.3.0 релизом). По сути это будут полностью протестированные релизы, просто в preview статусе, чтобы позволить нам вносить breaking changes
Re[2]: Invalid attempt of read when the reader is closed
От: Mace Windu  
Дата: 25.02.21 11:05
Оценка:
Здравствуйте, Mace Windu, Вы писали:

Вообще если хочется попробовать заставить это работать, то можно попробовать такое:
using (var db = new TestDB())
{
    db.BeginTransaction();
    IDbCommand command = null;
    foreach (var st in db.Entinies.Select(_ => _.UID))
    {
        if (command == null)
        {
            // сохраняем команду используемую с ридером для вызова Dispose после цикла
            command = db.Command;
            // отсоединяем команду от DataConnection, чтобы он создал новый инстанс для Update
            db.Command = null;
        }
        db.Items.Update(x => false, x => x);
    }
    // приправить try/finally по вкусу
    if (command != null) command.Dispose();

    db.CommitTransaction();
}
Re[2]: Invalid attempt of read when the reader is closed
От: Sharov Россия  
Дата: 09.04.21 15:08
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Я надеюсь это не рабочий код? Мы ж..у рвем чтобы у вас была возможность работать эффективно с базой, а тут цикл с апдейтами.


А в чем криминал, разве при коммите не батч отправится? Или каждый Update это доступ к бд?
Кодом людям нужно помогать!
Re[3]: Invalid attempt of read when the reader is closed
От: Danchik Украина  
Дата: 13.04.21 13:41
Оценка: 8 (1)
Здравствуйте, Sharov, Вы писали:

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


D>>Я надеюсь это не рабочий код? Мы ж..у рвем чтобы у вас была возможность работать эффективно с базой, а тут цикл с апдейтами.


S>А в чем криминал, разве при коммите не батч отправится? Или каждый Update это доступ к бд?


Именно, каждый апдейт это поход в базу.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.