EF Core otwieranie kilku połączeń do DB

0

Cześć,
Czy w EF core mimo że dbcontext jest wstrzykiwany, Database jest zawsze jeden wspólny? chodzi mi o DbContext.DataBase.
Już mówię w czym problem, mam metodę która otwiera sobie połączenie za pomocą await this.Database.OpenConnectionAsync(); wykonuje jakiś skrypt command.ExecuteReaderAsync() i na koniec zamyka połączenie await this.Database.CloseConnectionAsync();
Metoda jest wystawiona w moim DataContext, jest asynchroniczna, więc może być wywoływana z różnych endpointow.
Zauważyłem że w pewnym momencie mi umiera wywołanie takiego endpointa, analizując logi znalazłem że problem polega najprawdopodobniej na tym że jedno wywołanie zamyka połączenie drugiemu.
Tu też zauważyłem że połączenie do DB jest wspólne, ponieważ przy drugim wywołaniu w tym samym czasie OpenConnectionAsync zwróciło connection already open, więc pewnie się wykonało co miało i zamknęło, a drugie wywołanie w tym momencie utknęło prawdopodobnie gdzieś ExecuteReaderAsync.
Jak mogę się na coś takiego zabezpieczyć? mogę jakoś w OpenConnectionAsync tworzyć zawsze nowe, osobne połączenie?

0

Pytanie po co chcesz otwierać kilka połączeń do bazy? Co chcesz uzyskać?

0

A Jak context jest tworzony przed wstrzyknięciem?
Na pewno potrzebujesz ręcznego otwierania i zamykania?

0

Nie wiem czy jest mi to potrzebne :( szukałem sposobu na odpalanie customowego sql i znalazłem coś takiego już po mojej adaptacji:

            try
            {
                using (NpgsqlCommand command = new NpgsqlCommand(sql, (NpgsqlConnection)this.Database.GetDbConnection()))
                {
                    command.CommandType = CommandType.Text;
                    command.AllResultTypesAreUnknown = true;

                    if (this.Database.CanConnect())
                    {
                        await this.Database.OpenConnectionAsync();
                    }             
                    
                    using (DbDataReader result = await command.ExecuteReaderAsync())
                    {
                        
                    }
                }
            }
            catch (Exception ex)
            {
                //log
                throw;
            }
            finally
            {
                await this.Database.CloseConnectionAsync();
            }

I w przykładach właśnie połączenie było otwierane i zamykane, a teraz okazuje się że to połączenie nie jest w ramach DBContext tylko wychodzi na to że jest globalne.

Być może mogę usunąć open i close connection i problem się sam rozwiąże? a sql nadal się będzie wykonywał. A samo zamknięcie połączenia nastąpi jak na DBContext zostanie wykonany dispose po wykonaniu czynności w endpoincie?

Widziałem też przykłady w któych w NpgsqlCommand była metoda Open(), ale teraz już jej nie ma.

edit://

Zamieniłem to rzutowanie:
(NpgsqlConnection)this.Database.GetDbConnection())
na:
NpgsqlConnection connection = new NpgsqlConnection(this.Database.GetDbConnection().ConnectionString);

i teraz robie connection.OpenAsync() i connection.CloseAsync() mam nadzieję, że to mi rozwiąże problem.

0

DbContext nie jest thread safe, co oznacza, że nie możesz go używać równolegle, ani nawet nierównolegle, ale w różnych wątkach. Jeżeli chcesz go używać w wielu wątkach to musisz go instancjonować per wątek. A poza tym nie wiem skąd Ci się wzięło jakieś manualne otwieranie połączenia. Nie musisz tego robić. Poczytaj sobie jakieś tutoriale z EF Core, bo mam wrażenie, że nie masz pojęcia co robisz :P Połączenie zostanie zamknięte jeżeli obiekt zostanie zdisposowany, więc dopóki nie trzymasz gdzieś referencji do obiektu, to DbContext zostanie zdisposowany przez finalizera, którego odpali GC.

0

Robię to tak żeby odpalić customowe skrypty na DB, kiedyś w EF była osobna metoda do tego ale w nowszej wersji z niej zrezygnowano, więc znalazłem takie wyjście. Pewnie wiem co robię :) z EF korzystam od niedawna. Nie chodzi mi o to że odpalam coś w kilku wątkach recznie, ale o to że mam wystawione w dwóch kontrolerach metody POST. Do obu jest wstrzykiwany DBContext w momencie wywołania z zewnątrz, który ma metode moją powyżej i teraz jeśli się zdarzy że oba wywołania będą w identycznym czasie, to jeden drugiemu zamknie połączenie, mimo iż myślałem że to są osobne instancje.

0

@blane: o to Ci chodzi?
context.Database.ExecuteSqlCommand(sql)

0
blane napisał(a):

Do obu jest wstrzykiwany DBContext w momencie wywołania z zewnątrz, który ma metode moją powyżej i teraz jeśli się zdarzy że oba wywołania będą w identycznym czasie, to jeden drugiemu zamknie połączenie, mimo iż myślałem że to są osobne instancje.

A jak zarejestrowałeś DbContext w kontenerze?

Bo standardowe podejście jest takie, że masz instancję DbContextu per request i wtedy zamknięcie połączenia w jednym zapytaniu nie będzie miało wpływu na drugie.

0

Tak:

services.AddDbContext<DataContext>(x =>
            {
                x
                    .UseNpgsql($"Server={server}; Port={port}; Database={dataBase}; User Id={user}; Password={password}")
                    .UseLoggerFactory(loggerFactory);
            });

1 użytkowników online, w tym zalogowanych: 0, gości: 1