Задать вопрос

Как подключить БД Supabase к .Net проекту?

Нужно подключить БД к .Net WinForm проекту.
Реализация проекта должна быть с использованием PostgreSQL, поэтому выбрал Supabase.
Проблема в том, что как бы я не пытался, все время выдает одну и ту же ошибку
Запрошенное имя верно, но данные запрошенного типа не найдены
. Пробовал разные способы, но не помогало. На скрине полный стек с ошибками.
Какие есть идеи?
appsettings.json:
{
  "ConnectionStrings": {
    "DefaultConnection": "Host=db.chrbzfqlxbywuqbouoxe.supabase.co;Port=5432;Database=postgres;Username=postgres;Password=********;SSL Mode=Require;Trust Server Certificate=true"
  }
 }

Подключение к БД:
using Microsoft.Extensions.Configuration;
using Npgsql;
using System.Data;

namespace FitnessCenterManagement;

public class DatabaseConnection : IDisposable
{
    private readonly string _connectionString;
    private NpgsqlConnection? _connection;

    public DatabaseConnection()
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .Build();

        _connectionString = configuration.GetConnectionString("DefaultConnection")
            ?? throw new InvalidOperationException("Connection string not found in configuration.");
    }

    public async Task<NpgsqlConnection> GetConnectionAsync()
    {
        if (_connection == null || _connection.State != ConnectionState.Open)
        {
            _connection = new NpgsqlConnection(_connectionString);
            await _connection.OpenAsync();
        }
        return _connection;
    }

    public async Task CloseConnectionAsync()
    {
        if (_connection != null && _connection.State == ConnectionState.Open)
        {
            await _connection.CloseAsync();
            await _connection.DisposeAsync();
            _connection = null;
        }
    }

    public async Task<int> ExecuteNonQueryAsync(string sql, params NpgsqlParameter[] parameters)
    {
        await using var connection = new NpgsqlConnection(_connectionString);
        await connection.OpenAsync();

        await using var command = new NpgsqlCommand(sql, connection);

        if (parameters.Length > 0)
            command.Parameters.AddRange(parameters);

        return await command.ExecuteNonQueryAsync();
    }

    public async Task<DataTable> ExecuteQueryAsync(string sql, params NpgsqlParameter[] parameters)
    {
        await using var connection = new NpgsqlConnection(_connectionString);
        await connection.OpenAsync();

        await using var command = new NpgsqlCommand(sql, connection);

        if (parameters.Length > 0)
            command.Parameters.AddRange(parameters);

        var dataTable = new DataTable();
        using var reader = await command.ExecuteReaderAsync();
        dataTable.Load(reader);

        return dataTable;
    }

    public async Task<bool> UserExistsAsync(string login)
    {
        var sql = "SELECT COUNT(1) FROM fitness_centers WHERE login = @login";
        var parameters = new NpgsqlParameter[]
        {
            new("@login", login)
        };

        var result = await ExecuteQueryAsync(sql, parameters);
        return Convert.ToInt32(result.Rows[0][0]) > 0;
    }

    public async Task<bool> RegisterFitnessCenterAsync(string name, string login, string password, string address)
    {
        try
        {
            var existsSql = "SELECT COUNT(1) FROM fitness_centers WHERE login = @login";
            var existsParams = new NpgsqlParameter[]
            {
            new("@login", login)
            };

            var existsResult = await ExecuteQueryAsync(existsSql, existsParams);
            var count = Convert.ToInt32(existsResult.Rows[0][0]);

            if (count > 0)
            {
                Console.WriteLine($"User with login '{login}' already exists");
                return false;
            }

            var hashedPassword = BCrypt.Net.BCrypt.HashPassword(password);

            var insertSql = @"
            INSERT INTO fitness_centers (name, login, password, address, created_at)
            VALUES (@name, @login, @password, @address, @created_at)";

            var insertParams = new NpgsqlParameter[]
            {
            new("@name", name),
            new("@login", login),
            new("@password", hashedPassword),
            new("@address", address),
            new("@created_at", DateTime.UtcNow)
            };

            var rowsAffected = await ExecuteNonQueryAsync(insertSql, insertParams);

            Console.WriteLine($"Registration: {rowsAffected} rows affected");
            return rowsAffected > 0;
        }
        catch (PostgresException pgEx)
        {
            Console.WriteLine($"PostgreSQL Error: {pgEx.SqlState} - {pgEx.MessageText}");
            Console.WriteLine($"Detail: {pgEx.Detail}");
            throw;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"General Error: {ex.Message}");
            Console.WriteLine($"StackTrace: {ex.StackTrace}");
            throw;
        }
    }

    public void Dispose()
    {
        if (_connection != null)
        {
            if (_connection.State == ConnectionState.Open)
                _connection.Close();
            _connection.Dispose();
        }
    }
}

Использование:
using System;
using System.Data;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Extensions.Configuration;
using Npgsql;

namespace FitnessCenterManagement
{
    public partial class RegistrationMenuForm : Form
    {
        public RegistrationMenuForm()
        {
            InitializeComponent();
            _dbConnection = new DatabaseConnection();
            CenterUI();
            ApplyColorScheme();
            WireUpEvents();
        }

        private void ApplyColorScheme()
        {
            // Цвета
        }

        private void WireUpEvents()
        {
            _registerButton.Click += OnRegisterButtonClick;
            _backButton.Click += OnBackButtonClick;
            this.KeyPreview = true;
            this.KeyDown += OnFormKeyDown;
        }

        private async void OnRegisterButtonClick(object? sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(_nameTextBox.Text) ||
                string.IsNullOrWhiteSpace(_loginTextBox.Text) ||
                string.IsNullOrWhiteSpace(_passwordTextBox.Text) ||
                string.IsNullOrWhiteSpace(_addressTextBox.Text))
            {
                MessageBox.Show("Пожалуйста, заполните все поля", "Ошибка",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            if (_passwordTextBox.Text.Length < 6)
            {
                MessageBox.Show("Пароль должен содержать минимум 6 символов", "Ошибка",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            _registerButton.Enabled = false;
            _registerButton.Text = "Регистрация...";

            try
            {
                bool success = await _dbConnection.RegisterFitnessCenterAsync(
                    _nameTextBox.Text.Trim(),
                    _loginTextBox.Text.Trim(),
                    _passwordTextBox.Text,
                    _addressTextBox.Text.Trim()
                );

                if (success)
                {
                    MessageBox.Show("Регистрация успешно завершена!", "Успех",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);

                    this.Close();
                }
                else
                {
                    MessageBox.Show("Пользователь с таким логином уже существует", "Ошибка",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (PostgresException pgEx)
            {
                string errorMessage = pgEx.SqlState switch
                {
                    "23505" => "Пользователь с таким логином уже существует",
                    "28P01" => "Ошибка аутентификации. Проверьте пароль подключения",
                    "3D000" => "База данных не найдена",
                    "08006" => "Соединение разорвано. Проверьте настройки сети",
                    _ => $"Ошибка базы данных: {pgEx.Message}"
                };

                MessageBox.Show(errorMessage, "Ошибка базы данных",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"General Error: {ex.Message}");
                Console.WriteLine($"StackTrace: {ex.StackTrace}");
                MessageBox.Show($"Ошибка при регистрации: {ex.Message}.\nОшибка стека: {ex.StackTrace}", "Ошибка",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                _registerButton.Enabled = true;
                _registerButton.Text = "Зарегистрировать";
            }
        }

        private void OnBackButtonClick(object? sender, EventArgs e)
        {
            this.Close();
        }

        private void OnFormKeyDown(object? sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && e.Control)
            {
                OnRegisterButtonClick(this, EventArgs.Empty);
            }
            else if (e.KeyCode == Keys.Escape)
            {
                this.Close();
            }
        }
    }
}

P.S. Я знаю, что есть отдельная библиотека Supabase для C#, но у меня задание, реализовать в таком формате.
Ошибка -
696082dfdb7a1775011260.png
  • Вопрос задан
  • 97 просмотров
Подписаться 1 Простой 1 комментарий
Помогут разобраться в теме Все курсы
  • Skillfactory
    Профессия C#-разработчик
    12 месяцев
    Далее
  • Merion Academy
    C# разработчик с нуля
    4 месяца
    Далее
  • Stepik
    PRO C#. Профессия "Backend разработчик"
    4 месяца
    Далее
Решения вопроса 1
NeiroNx
@NeiroNx
Программист
Имя хоста похоже не верное. Падает на разрешении имен. Попробуйте на локальной базе. Подключитесь какимнибудь DB клиентом с той машины где скрипт работает.
Возможно надо работать через DNS сервиса supabase.co
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы