Member 13624040 Ответов: 2

Как правильно использовать соединение sqlite в нескольких формах?


У меня есть два класса в моем приложении C#.
Я инициирую и открываю соединение с БД в main.cs

public static void dbConnect()
       {
           string dbPath = Application.StartupPath + "/database.db";

           SQLiteConnection conn = new SQLiteConnection("Data Source =" + dbPath);

           conn.Open();

       }


У меня есть еще одна форма Add.cs, где я пытаюсь заполнить combobox из базы данных. Как только я это делаю, combobox заполняется, но после того, как я закрываю Add.cs и функция в main.cs пытается использовать объект conn, она выдает мне ошибку
Cannot access a disposed object object name: 'sqliteconnection'


Что я уже пробовал:

Вот как я попытался получить доступ к БД, используя вторую форму

private void AddStore_Load(object sender, EventArgs e)
       {
           using (frmMain.conn)
           {
               try
               {
                   string query = "SELECT * FROM routes;";
                   SQLiteDataAdapter da = new SQLiteDataAdapter(query, frmMain.conn);
                   DataSet ds = new DataSet();
                   da.Fill(ds, "routes");
                   cmbRoute.DisplayMember = "route_name";
                   cmbRoute.ValueMember = "route_id";
                   cmbRoute.DataSource = ds.Tables["routes"];
               }
               catch (Exception ex)
               {
                   MessageBox.Show("Error "+ex);
               }
           }
       }



Поскольку это не сработало, я попытался создать новую строку подключения с теми же деталями и повторно подключиться к БД, и это сработало

private void AddStore_Load(object sender, EventArgs e)
        {
            string dbPath = Application.StartupPath + "/database.db";
            using (SQLiteConnection conn = new SQLiteConnection("Data Source =" + dbPath))
            {
                try
                {
                    string query = "SELECT * FROM routes;";
                    SQLiteDataAdapter da = new SQLiteDataAdapter(query, frmMain.conn);
                    DataSet ds = new DataSet();
                    da.Fill(ds, "routes");
                    cmbRoute.DisplayMember = "route_name";
                    cmbRoute.ValueMember = "route_id";
                    cmbRoute.DataSource = ds.Tables["routes"];
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error "+ex);
                }
            }
        }


Но я скептически отношусь к этому методу, потому что он создает несколько подключений к одной и той же БД.

2 Ответов

Рейтинг:
2

OriginalGriff

Проблема заключается в том, что как только объект выходит за пределы области видимости, он больше не доступен и может быть удален сборщиком мусора в любое время. И если вы создадите его как часть using заголовок, то он явно утилизируется, когда выходит за пределы области видимости.

Так что когда вы это сделаете:

public static void dbConnect()
       {
           string dbPath = Application.StartupPath + "/database.db";

           SQLiteConnection conn = new SQLiteConnection("Data Source =" + dbPath);

           conn.Open();

       }
Объект connдоступен только в контексте этого метода, если только вы не сохраните ссылку на него во внешней переменной.
И когда вы это сделаете:
private void AddStore_Load(object sender, EventArgs e)
        {
            string dbPath = Application.StartupPath + "/database.db";
            using (SQLiteConnection conn = new SQLiteConnection("Data Source =" + dbPath))
            {
...
            }
        }
То conn объект явно расположен в конце строки. using блок, даже если вы сохраняете ссылку на него.

SQL-соединение и командные объекты-это дефицитные ресурсы, и вы должны создавать-использовать - утилизировать их как само собой разумеющееся - вы не должны пытаться использовать соединение из другой формы, потому что вы абсолютно не знаете, в каком состоянии оно находится-Вы даже не знаете, была ли эта форма отображена (если только ваш код не очень хорошо организован, и в этом случае это наименьшая из ваших проблем).

Изменение, которое я бы сделал, состоит в том, чтобы иметь статический класс, содержащий статическое свойство или метод, который возвращает допустимую строку соединений (вместо жесткого кодирования ее можно прочитать из конфигурационного файла) и использовать эту строку каждый раз, когда вам нужно соединение.

(Я иду дальше, и у меня есть внешний магазин, который содержит их: Хранилище экземпляров - простой способ обмена конфигурационными данными между приложениями[^] - но это может быть излишним для вашего приложения.)


Member 13624040

И вот что я сделал:
Я добавил строку подключения в файл App.config
Я создал новый общедоступный статический класс "диспетчер соединений"
Я создал общедоступный статический метод, который возвращает SQLiteConnection
В своей основной форме я использовал
SQLiteConnection conn = ConnectionManager.Метод getconnection();
Коннектикут.Открыть();

Звучит ли это правильно?
Это работает, но мне нужно следовать правильным путем.

Рейтинг:
0

F-ES Sitecore

Вы должны создавать соединения, когда они вам нужны, и закрывать их, когда вы этого не делаете, как это позволяет ado.net пул соединений для работы. Таким образом, ваш обновленный пример хорош, однако вы можете упростить его, удерживая строку подключения в разделе connectionStrings конфигурации приложения и используя классы конфигурации для доступа к ней, а не жестко кодировать строку каждый раз, когда вы ее используете. Или вы можете создать статическую вспомогательную функцию, которая вернет коду соединение

public static class ConnectionHelper
{
    public static SQLiteConnection GetConnection()
    {
       ... create and return the connection object
    }
}


Когда вам понадобится связь просто позвоните

ConnectionHelper.Метод getconnection

а когда вам это больше не понадобится, позвоните своим .Закройте и\or .Dispose метод на нем. Однако в наши дни этот тип решения не одобряется, поскольку он не поддается тестируемому коду, поэтому лучше использовать configuration manager для получения строки подключения (google "c# manage connection strings" для получения дополнительной информации).


Member 13624040

Я использовал ваш ответ и оригинальный ответ Гриффа и вот что я сделал

Я добавил строку подключения в файл App.config
Я создал новый общедоступный статический класс "диспетчер соединений"
Я создал общедоступный статический метод, который возвращает SQLiteConnection
В своей основной форме я использовал
SQLiteConnection conn = ConnectionManager.Метод getconnection();
Коннектикут.Открыть();

Звучит ли это правильно?
Это работает, но мне нужно следовать правильным путем.

F-ES Sitecore

Да, если это сработает, то все в порядке. Философия связей заключается в том, чтобы открывать их как можно позже и закрывать как можно быстрее. Поэтому откройте соединение прямо перед тем, как использовать его для выполнения чего-то, и закройте его сразу после этого. Чем меньше времени вы используете его, тем больше он доступен для использования другим кодом.