projekt_forum.dll


Parikon

Rekomendowane odpowiedzi

Musimy wytłumaczyć sobie jedno. Ja tutaj nie chcę,  aby kojarzono mnie z jakimś nauczycielem. Chcę tylko pokazać jak ja to zrobiłem, co pokazałem na początku. Ale w zasadzie już odszedłem od schematu, którego musiałbym się trzymać aby dojść do efektu końcowego. Projekt zatem już żyje swoim własnym życiem. Nie korzystałem z interfejsów, a nawet jak gdzieś korzystałem to nie tworzyłem ich w klasach i zapewne jeszcze nie rozumiem ich działania. Ale ok, dodałem to co proponuje kolega. Zasadniczo ten interfejs jest do wyboru. Wygląda to tak:

using System.Data.SQLite;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;

namespace projekty
{
    class Base
    {


        public interface IBase
        {
            bool AddBaseIfNotExist();
            int GetBaseVersion();
        }


        /// <summary>
        /// Tworzy bazę jeśli nie istnieje i tabelę projekt_lista, jesli coś się nie powiodło zwraca false 
        /// </summary>
        public static bool AddBaseIfNotExist()
        {
            bool ok;
            try
            {
                string path = (new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath;
                //wyodrębniamy ściężkę do katalogu i jesli nie istnieje tworzymy naszą bazę
                string sciezka = System.IO.Path.GetDirectoryName(path) + "\\Bazy" + "\\projekty.sqlite";
                SQLiteConnection db_con = new SQLiteConnection("Data Source = " + sciezka + "; Version = 3");
                //utworzenie tabeli
                db_con.Open();
                SQLiteCommand db_cmd = db_con.CreateCommand();
                db_cmd.CommandType = CommandType.Text;
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS projekt_lista ([Numer projektu]  INT, [Nazwa projektu]  TEXT, [Data dodania] TEXT, [Data zakończenia] TEXT, [Ścieżka] TEXT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS wersja_bazy ([Numer wersji]  INT)";
                db_cmd.ExecuteNonQuery();
                db_con.Close();
                ok = true;                
            }
            catch
            {
                MessageBox.Show("Nie utworzono bazy. Prawdopodobnie brak możliwości zapisu w katalogu z programem lub brak katalogu Bazy. Program zostanie zamknięty", "Projekty-info");
                ok = false;
            }
            return ok;                
        }

        public static int GetBaseVersion()
        
        {
            int wersja = 1; // nasz program tworzy taką wersję
            // tutaj kod, który sprawdzi czy jest rekord, wpisze wersje jesli nie ma rekordu lub odczyta jeśli wersja jest już wpisana (baza już istnieje)
			//przydałoby sie go w końcu napisać
            return wersja; // metoda zwróci wersję
        }

    }
}

a tutaj MainWindow

using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace projekty
{
    /// <summary>
    /// Logika interakcji dla klasy MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
           bool results = Base.AddBaseIfNotExist();
            if (results != true)
            {
                Window.GetWindow(this).Close();
            }
            else if (Base.GetBaseVersion() != 1)
            {
                // tutaj dałbym konwerter ze starej bazy na nową, ale narazie nie mamy takiego konwertera więc program tego nie zrobi oraz nawet nie wiem jakmiałby wyglądać kod
                MessageBox.Show("Nieprawidłowa wersja bazy. Konwersja niemożliwa w tej wersji programu.Nastąpi zamknięcie programu", "Projekty-info");
                Window.GetWindow(this).Close();                
            }
        }        
    }
}

 

Edytowane przez Parikon
Odnośnik do komentarza
Udostępnij na innych stronach

ok, próbujemy stworzyć bazę i wysypujemy się jeśli nie ma katalogu??? to może najpierw sprawdźmy czy jest katalog i jeśli go nie ma to go stwórzmy.

 

using System.IO;
....
string path = (new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath;
string sciezkaBaza = System.IO.Path.GetDirectoryName(path) + "\\Bazy";  
if(!Directory.Exists(sciezkaBaza))
{
    Directory.CreateDirectory(sciezkaBaza);
}
Edytowane przez s1016
Odnośnik do komentarza
Udostępnij na innych stronach

Mi takie coś działa:

            var dbPath = "D:\\dev\\Visual Studio 2017 Community";
            var dbName = "projekty.sqlite3";
            Directory.CreateDirectory($"{dbPath}");
            connection = new SQLiteConnection($"Data Source = {dbPath}\\{dbName}; Version = 3");

Może wstaw u siebie 

Directory.CreateDirectory($"{sciezkaBaza}");

 

Edytowane przez perlon
Odnośnik do komentarza
Udostępnij na innych stronach

Problem jest prosty do zdiagnozowania:

W przypadku gdy jakikolwiek folder w ścieżce będzie miał nazwę ze spacją to program pobiera taki np string jak u mnie: D:/Projekty%20baza/projekty.exe, a w rzeczywistości ścieżka to D:/Projekty baza/projekty.exe. Co się zatem dzieje, że jednak program nie wysypuje się. Ano u mnie po dodaniu kodu sprawdzającego czy jest katalog baza i jeśli nie to utwórz program utworzył bazę i całą ścieżkę D:/Projekty%20baza/Bazy 😉

Odnośnik do komentarza
Udostępnij na innych stronach

Dnia 15.11.2017 o 20:12, Parikon napisał:

W tym temacie chciałbym od podstaw rozpocząć tworzenie nakładki zawartej w jednym pliku z rozszerzeniem dll. Tematem nakładki będzie lista projektów. Temat ten ma za zadanie zachęcić niektórych forumowiczów (tych którzy się "zarażą") do tworzenia aplikacji uruchamianych bezpośrednio z ZwCAD-a i nauki C#. Kod programu będzie w pełni dostępny w tym temacie na zasadzie bierz i używaj , a jak chcesz to dodaj coś od siebie. Sam osobiście nie czuję się ekspertem, ale tym co już potrafię postaram się  dojść do ciekawego efektu.

 

 

 

2 godziny temu, Parikon napisał:

Chcę tylko pokazać jak ja to zrobiłem, co pokazałem na początku. Ale w zasadzie już odszedłem od schematu, którego musiałbym się trzymać aby dojść do efektu końcowego.

Jeszcze raz wróciłem do pierwszego posta i po chwili refleksji chciałbym Parikona przeprosić. Źle odczytałem intencję. Jako gospodarz tego wątku pokazuje swoją drogę do wyznaczonego w zamyśle efektu końcowego zaznaczając że powstaje tu kod "as is". Być może odniosłem mylne wrażenie, że moglibyśmy wspólnie jako użytkownicy forum zainteresowani programowaniem wypracować rozwiązania, które będą swego rodzaju efektem wspólnego uczenia się. Niemniej jednak z zainteresowaniem będę obserwował rozwój tego narzędzia. Miałbym również propozycję (nie wiem czy możliwą technicznie) aby w pierwszym poście umieścić link do zasobu zawierającego aktualny stan kompletnego kodu - najlepiej całej solucji. Będzie to pomocne przy indywidualnym testowaniu programu. Być może wystąpią przypadki użycia nie uwzględnione przez autora. Zgłoszenia takie zapewne będą pomocne w rozwoju nakładki.

Odnośnik do komentarza
Udostępnij na innych stronach

Nowy kod powinien rozwiązać problem.Chociaż wolałbym stałą path mieć dostępną w klasie Base, ale nie wiem jak to zrobić

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;

namespace projekty
{
    class Base
    {


        public interface IBase
        {
            bool AddBaseIfNotExist();
            int GetBaseVersion();
        }


        /// <summary>
        /// Tworzy bazę jeśli nie istnieje i tabelę projekt_lista, jesli coś się nie powiodło zwraca false 
        /// </summary>
        public static bool AddBaseIfNotExist(string path)
        {
            
            bool ok;
            try
            {               
                //wyodrębniamy ściężkę do katalogu i jesli nie istnieje tworzymy katalog  Bazy
                string sciezkaBaza = path + "\\Bazy";                
                if (!Directory.Exists(sciezkaBaza)){Directory.CreateDirectory(sciezkaBaza);}
                //scieżka do bazy
                string sciezka = sciezkaBaza + "\\projekty.sqlite";
                SQLiteConnection db_con = new SQLiteConnection("Data Source = " + sciezka + "; Version = 3");
                //utworzenie tabeli
                db_con.Open();
                SQLiteCommand db_cmd = db_con.CreateCommand();
                db_cmd.CommandType = CommandType.Text;
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS projekt_lista ([Numer projektu]  INT, [Nazwa projektu]  TEXT, [Data dodania] TEXT, [Data zakończenia] TEXT, [Ścieżka] TEXT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS wersja_bazy ([Numer wersji]  INT)";
                db_cmd.ExecuteNonQuery();
                db_con.Close();
                ok = true;                
            }
            catch
            {
                MessageBox.Show("Nie utworzono bazy. Prawdopodobnie brak możliwości zapisu w katalogu z programem lub brak katalogu Bazy. Program zostanie zamknięty", "Projekty-info");
                ok = false;
            }
            return ok;                
        }

        public static int GetBaseVersion()
        
        {
            int wersja = 1; // nasz program tworzy taką wersję
            // tutaj kod, który sprawdzi czy jest rekord, wpisze wersje jesli nie ma rekordu lub odczyta jeśli wersja jest już wpisana (baza już istnieje)
            return wersja; // metoda zwróci wersję
        }

    }
}

Pobieramy ścieżkę zgodnie z tym co podał @s1016

using System.Data.SQLite;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace projekty
{
    /// <summary>
    /// Logika interakcji dla klasy MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            string path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location));
            

            bool results = Base.AddBaseIfNotExist(path);
            if (results != true)
            {
                Window.GetWindow(this).Close();
            }
            else if (Base.GetBaseVersion() != 1)
            {
                // tutaj dałbym konwerter na starej bazy na nową, ale narazie nie mamy takiego konwertera więc program tego nie zrobi
                MessageBox.Show("Nieprawidłowa wersja bazy. Konwersja niemożliwa w tej wersji programu.Nastąpi zamknięcie programu", "Projekty-info");
                Window.GetWindow(this).Close();                
            }
        }        
    }
}

@Perlon już tworzymy całkiem inny kod i jestem z tego bardzo ucieszony. 

No i jesteśmy w domu. Teraz możemy debugować bezpośrednio w Visual Studio, gdyż to był problem, że debugger nie mógł utworzyć bazy w katalogu bin.

 

Edytowane przez Parikon
Odnośnik do komentarza
Udostępnij na innych stronach

Żeby mieć zmienną path dostępną wewnątrz klasy dla metod trzeba mieć instancję klasy i przekazać wartość przez konstruktor klasy:

    public class Base
    {
        string path;

        public Base(string _path)
        {
            this.path = _path;
        }

        public bool AddBaseIfNotExist()
        {
            
            bool ok;
            try
            {
                string sciezkaBaza = this.path + "\\Bazy";
                // 
            }
            catch
            {
                // ...
            }
            return ok;
        }
    }

Żeby zadziałało trzeba powoływać obiekt klasy Base() a metoda już bez argumentu bo klasa ma pole path.

var base = new Base(path);
var result = base.AddBaseIfNotExist();

Jeżeli pole statyczne w klasie Base() to można tak :

public static string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

 

Odnośnik do komentarza
Udostępnij na innych stronach

Aby było wykorzystane więcej możliwości jakie daje język to skorzystamy z konstruktora tak jak radzi @perlon. Z tego co poczytałem metoda konstruktora musi mieć nazwę identyczną jak nazwa klasy, w której ją tworzymy.

namespace projekty
{
    /// <summary>
    /// Logika interakcji dla klasy MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        string path;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location));
            var baza = new Base(path);
            bool results = baza.AddBaseIfNotExist();
            if (results != true)
            {
                Window.GetWindow(this).Close();
            }
            else if (baza.GetBaseVersion() != 1)
            {
                // tutaj dałbym konwerter na starej bazy na nową, ale narazie nie mamy takiego konwertera więc program tego nie zrobi
                MessageBox.Show("Nieprawidłowa wersja bazy. Konwersja niemożliwa w tej wersji programu.Nastąpi zamknięcie programu", "Projekty-info");
                Window.GetWindow(this).Close();                
            }
        }        
    }
}
namespace projekty
{
    class Base
    {
        string path;  
        
        /// <summary>
        /// Konstruktor klasy. Pobiera ścieżkę do bazy.
        /// </summary>
        /// <param name="_path"></param>
        
        public Base(string _path)
        {
            this.path = _path;
        }

        public interface IBase
        {
            bool AddBaseIfNotExist();
            int GetBaseVersion();
        }
        /// <summary>
        /// Tworzy bazę jeśli nie istnieje i tabelę projekt_lista, jesli coś się nie powiodło zwraca false 
        /// </summary>
        public bool AddBaseIfNotExist()
        {
            
            bool ok;
            try
            {               
                //wyodrębniamy ściężkę do katalogu i jesli nie istnieje tworzymy katalog  Bazy
                string sciezkaBaza = this.path + "\\Bazy";                
                if (!Directory.Exists(sciezkaBaza)){Directory.CreateDirectory(sciezkaBaza);}
                //scieżka do bazy
                string sciezka = sciezkaBaza + "\\projekty.sqlite";
                SQLiteConnection db_con = new SQLiteConnection("Data Source = " + sciezka + "; Version = 3");
                //utworzenie tabeli
                db_con.Open();
                SQLiteCommand db_cmd = db_con.CreateCommand();
                db_cmd.CommandType = CommandType.Text;
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS projekt_lista ([Numer projektu]  INT, [Nazwa projektu]  TEXT, [Data dodania] TEXT, [Data zakończenia] TEXT, [Ścieżka] TEXT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS wersja_bazy ([Numer wersji]  INT)";
                db_cmd.ExecuteNonQuery();
                db_con.Close();
                ok = true;                
            }
            catch
            {
                MessageBox.Show("Nie utworzono bazy. Prawdopodobnie brak możliwości zapisu w katalogu z programem lub brak katalogu Bazy. Program zostanie zamknięty", "Projekty-info");
                ok = false;
            }
            return ok;                
        }

        public int GetBaseVersion()
        
        {
            int wersja = 1; // nasz program tworzy taką wersję
            // tutaj kod, który sprawdzi czy jest rekord, wpisze wersje jesli nie ma rekordu lub odczyta jeśli wersja jest już wpisana (baza już istnieje)
            return wersja; // metoda zwróci wersję
        }

    }
}


 

Odnośnik do komentarza
Udostępnij na innych stronach

Propozycja dokończenia metody GetBaseVersion(). 

public int GetBaseVersion()
        
        {
            int wersja = 1; // nasz program tworzy taką wersję
            string sciezka = this.path + "\\Bazy" + "\\projekty.sqlite";
            SQLiteConnection db_con = new SQLiteConnection("Data Source = " + sciezka + "; Version = 3");
            db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "select * from wersja_bazy";
            db_cmd.ExecuteNonQuery();
            var dt = new DataTable();
            SQLiteDataAdapter da = new SQLiteDataAdapter(db_cmd);
            da.Fill(dt);           
            int wierszy = dt.Rows.Count;            
            if (wierszy == 0)
            {                                
                db_cmd.CommandText = "INSERT INTO wersja_bazy VALUES ('1')";
                db_cmd.ExecuteNonQuery();
                db_con.Close();
            }
            else
            {
                DataRow dtr = dt.Rows[0];
                wersja = Convert.ToInt16(dtr[0]);
                db_con.Close();
            }
            return wersja; // metoda zwróci wersję
        }

 

Odnośnik do komentarza
Udostępnij na innych stronach

A może taka wersja klasy Base() :

    public class Base
    {
        // zmienna path nie jest potrzebna w zadnej z metod
        // można ją spokojnie przenieść do konstruktora jako zmienną prywatną
        // ale może się przyda więc zostaje
        private string path;
        // do połączenia wystarczy db_con ustawiony raz w konstruktorze
        private SQLiteConnection db_con;

        public Base(string _path)
        {
            // w zasadzie path nie jest potrzebny poza konstruktorem
            // żeby połaczyć sie ponownie z bazą w poszczególnyhc metodach wystarczy
            // zapamietać obiekt SQLiteConnection db_con
            this.path = _path + "\\Bazy";
            if (!Directory.Exists(this.path))
            {
                Directory.CreateDirectory(this.path);
                if (!Directory.Exists(this.path))
                {
                    throw new Exception("Błąd zakładania katalogu z bazą");
                }
            }
            string sciezkaBaza = this.path + "\\projekty.sqlite";
            this.db_con = new SQLiteConnection($"Data Source = {sciezkaBaza}; Version = 3");
        }

        public bool AddBaseIfNotExist()
        {
            bool ok;
            try
            {
                this.db_con.Open();
                SQLiteCommand db_cmd = db_con.CreateCommand();
                db_cmd.CommandType = CommandType.Text;
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS projekt_lista ([Numer projektu]  INT, [Nazwa projektu]  TEXT, [Data dodania] TEXT, [Data zakończenia] TEXT, [Ścieżka] TEXT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS wersja_bazy ([Numer wersji]  INT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "INSERT INTO wersja_bazy VALUES (1)";
                db_cmd.ExecuteNonQuery();
                this.db_con.Close();
                ok = true;
            }
            catch
            {
                MessageBox.Show("Nie utworzono bazy. Prawdopodobnie brak możliwości zapisu w katalogu z programem lub brak katalogu Bazy. Program zostanie zamknięty", "Projekty-info");
                ok = false;
            }
            return ok;
        }

        public long GetBaseVersion()
        {
            long result = 0;
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandText = "SELECT MAX([Numer wersji]) FROM wersja_bazy";
            var version = db_cmd.ExecuteScalar();
            this.db_con.Close();

            if (version == DBNull.Value)
            {
                throw new Exception("Tabela wersja_bazy powinna zawierać co najmniej jeden rekord. Coś poszło nie tak przy zakładaniu tej tabeli");
            } 
            else
            {
                result = (long)version;
            }
 
            return result;
        }
    }

 

Edytowane przez perlon
Odnośnik do komentarza
Udostępnij na innych stronach

Faktycznie nie przemyślałem tego do końca. Teraz powinno być lepiej.

        public bool AddBaseIfNotExist()
        {
            bool ok;
            try
            {
                this.db_con.Open();
                SQLiteCommand db_cmd = db_con.CreateCommand();
                db_cmd.CommandType = CommandType.Text;
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS projekt_lista ([Numer projektu]  INT, [Nazwa projektu]  TEXT, [Data dodania] TEXT, [Data zakończenia] TEXT, [Ścieżka] TEXT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'wersja_bazy'";
                var result = db_cmd.ExecuteScalar();
                if(result == DBNull.Value)
                {
                    db_cmd.CommandText = "CREATE TABLE wersja_bazy ([Numer wersji]  INT)";
                    db_cmd.ExecuteNonQuery();
                    db_cmd.CommandText = "INSERT INTO wersja_bazy VALUES (1)";
                    db_cmd.ExecuteNonQuery();
                }
                this.db_con.Close();
                ok = true;
            }
            catch( Exception ex )
            {
                MessageBox.Show(ex.Message, "Projekty-info");
                ok = false;
            }
            return ok;
        }

 

Edytowane przez perlon
Odnośnik do komentarza
Udostępnij na innych stronach

Czy gdy nie powstanie z jakiś powodów połączenie z bazą, gdyż program jak jej nie będzie, nie będzie jej mógł także utworzyć to po komunikacie

Błąd zakładania katalogu z bazą

Program wyświetli następny komunikat.

MessageBox.Show(ex.Message, "Projekty-info");

Czyli będziemy mieli dwa okna z komunikatami, które trzeba zamknąć. A przecież wystąpienie pierwszego komunikatu powinno już być przesłaniem do zamknięcia programu.

public Base(string _path)
        {
            this.path = _path + "\\Bazy";
            string sciezkaBaza = this.path + "\\projekty.sqlite";
            this.db_con = new SQLiteConnection($"Data Source = {sciezkaBaza}; Version = 3");
        }
 public bool AddBaseIfNotExist()
        {
            
            bool ok;
            try
            {
                if (!Directory.Exists(this.path))
                {
                    Directory.CreateDirectory(this.path);
                }
                this.db_con.Open();
                SQLiteCommand db_cmd = db_con.CreateCommand();
                db_cmd.CommandType = CommandType.Text;
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS projekt_lista ([Numer projektu]  INT, [Nazwa projektu]  TEXT, [Data dodania] TEXT, [Data zakończenia] TEXT, [Ścieżka] TEXT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS wersja_bazy ([Numer wersji]  INT)";
                db_cmd.ExecuteNonQuery();
                this.db_con.Close();
                ok = true;                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Projekty-info");
                ok = false;
            }
            return ok;                
        }

 

Edytowane przez Parikon
Odnośnik do komentarza
Udostępnij na innych stronach

Hmmm... Nie bardzo kumam. Zamiast 

            catch
            {
                MessageBox.Show("Nie utworzono bazy. Prawdopodobnie brak możliwości zapisu w katalogu z programem lub brak katalogu Bazy. Program zostanie zamknięty", "Projekty-info");
                ok = false;
            }
            return ok;

zaproponowałem 

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Projekty-info");
                ok = false;
            }
            return ok;                

Powyższe wyświetla faktyczną przyczynę skoku do bloku catch. Powrót do kodu :

            bool results = baza.AddBaseIfNotExist();
            if (results != true)
            {
                Window.GetWindow(this).Close();
            }
 

w zasadzie kończy sprawę. Kod 

            if (!Directory.Exists(this.path))
            {
                Directory.CreateDirectory(this.path);
                if (!Directory.Exists(this.path))
                {
                    throw new Exception("Błąd zakładania katalogu z bazą");
                }
            }
            string sciezkaBaza = this.path + "\\projekty.sqlite";
            this.db_con = new SQLiteConnection($"Data Source = {sciezkaBaza}; Version = 3");
        }

rzuca wyjątek w konstruktorze bez jego obsługi. Nie jest zamknięty w żadnym try catch więc powinien wywalić aplikację zanim dojdzie do metody AddBaseIfNotExist

Edytowane przez perlon
Odnośnik do komentarza
Udostępnij na innych stronach

No właśnie o to mi chodzi. Wyskoczy pierwszy komunikat po kliknięciu ok co? Wywali program zamiast zamknąć bezpiecznie okno. Być może to nie nastąpi, ale nie mam tu pewności. 

Jeśli chodzi o catch(Exception ex) to przecież właśnie ująłem to co proponowałeś w kodzie zamiast własnego komunikatu.

Edytowane przez Parikon
Odnośnik do komentarza
Udostępnij na innych stronach

Można wywalić obsługę wyjątków z klasy Base() pozostawiając rzucanie wyjątków. Być może trzeba "zagęścić" rzucanie wyjątków. Być może trzeba stworzyć specjalny typ dziedziczący po Exception().

    public class Base
    {
        // zmienna path nie jest potrzebna w zadnej z metod
        // można ją spokojnie przenieść do konstruktora jako zmienną prywatną
        private string path;
        // do połączenia wystarczy db_con ustawiony raz w konstruktorze
        private SQLiteConnection db_con;

        public Base(string _path)
        {
            // w zasadzie path nie jest potrzebny poza konstruktorem
            // żeby połaczyć sie ponownie z bazą w poszczególnyhc metodach wystarczy
            // zapamietać obiekt SQLiteConnection db_con
            this.path = _path + "\\Bazy";
            if (!Directory.Exists(this.path))
            {
                Directory.CreateDirectory(this.path);
                if (!Directory.Exists(this.path))
                {
                    throw new Exception("Błąd zakładania katalogu z bazą");
                }
            }
            string sciezkaBaza = this.path + "\\projekty.sqlite";
            this.db_con = new SQLiteConnection($"Data Source = {sciezkaBaza}; Version = 3");
        }

        public bool AddBaseIfNotExist()
        {
            bool ok = true;
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS projekt_lista ([Numer projektu]  INT, [Nazwa projektu]  TEXT, [Data dodania] TEXT, [Data zakończenia] TEXT, [Ścieżka] TEXT)";
            db_cmd.ExecuteNonQuery();
            db_cmd.CommandText = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'wersja_bazy'";
            var result = db_cmd.ExecuteScalar();
            if (result == DBNull.Value)
            {
                db_cmd.CommandText = "CREATE TABLE wersja_bazy ([Numer wersji]  INT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "INSERT INTO wersja_bazy VALUES (1)";
                db_cmd.ExecuteNonQuery();
            }
            this.db_con.Close();

            return ok;
        }

        public long GetBaseVersion()
        {
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandText = "SELECT MAX([Numer wersji]) FROM wersja_bazy";
            var version = db_cmd.ExecuteScalar();
            this.db_con.Close();

            if (version == DBNull.Value)
            {
                throw new Exception("Tabela wersja_bazy powinna zawierać co najmniej jeden rekord. Coś poszło nie tak przy zakładaniu tej tabeli");
            } 
            else
            {
                return (long)version;
            }
        }
    }

W każdym bądź razie co by się nie stało, obsługa wyjątku może być tu i będzie tylko jedno miejsce "wyskoku" z programu.

            try
            {
               var baza = new Base(path);
                if (baza.AddBaseIfNotExist()) {
                    if (baza.GetBaseVersion() != 1)
                    {
                        // tutaj dałbym konwerter na starej bazy na nową, ale narazie nie mamy takiego konwertera więc program tego nie zrobi
                        throw new Exception("Nieprawidłowa wersja bazy. Konwersja niemożliwa w tej wersji programu.Nastąpi zamknięcie programu");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Projekty-info");
                this.Close();
            }

 

Edytowane przez perlon
Odnośnik do komentarza
Udostępnij na innych stronach

@Perlon, program, nie być może, a na pewno, można napisać na wiele sposobów. Coś bardziej skomplikowanego niż jedno zdanie może być niepowtarzalne. Zatem proszę o konkrety. Bo na razie podajesz inne rozwiązania robiące w zasadzie to samo. Dlaczego long a nie int? Jakie jest poważne uzasadnienie zamiany. itp. 😉

Podaję co mam:

<Window x:Name="main" x:Class="projekty.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:projekty"
        mc:Ignorable="d"
        Title="Lista projektów" Height="450" Width="800" Loaded="Window_Loaded">
    <Grid>
        <TabControl >
            <TabItem Header="Baza">
                <TabItem.Background>
                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                        <GradientStop Color="#FFF0F0F0" Offset="0"/>
                        <GradientStop Color="#FF424B56" Offset="1"/>
                    </LinearGradientBrush>
                </TabItem.Background>
                <Grid Background="#FF424B56">
                    <Button x:Name="button_dodaj" Content="Dodaj" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Foreground="White" BorderBrush="White">
                        <Button.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="Black" Offset="0"/>
                                <GradientStop Color="White" Offset="1"/>
                            </LinearGradientBrush>
                        </Button.Background>
                    </Button>
                    <Button x:Name="button_zmien" Content="Zmień" HorizontalAlignment="Left" Margin="90,10,0,0" VerticalAlignment="Top" Width="75" Foreground="White" BorderBrush="White">
                        <Button.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="Black" Offset="0"/>
                                <GradientStop Color="White" Offset="1"/>
                            </LinearGradientBrush>
                        </Button.Background>
                    </Button>
                    <Button x:Name="button_usun" Content="Usuń" HorizontalAlignment="Left" Margin="170,10,0,0" VerticalAlignment="Top" Width="75" Foreground="White" BorderBrush="White">
                        <Button.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="Black" Offset="0"/>
                                <GradientStop Color="White" Offset="1"/>
                            </LinearGradientBrush>
                        </Button.Background>
                    </Button>
                    <Button x:Name="button_aktualny" Content="Aktualny" HorizontalAlignment="Left" Margin="250,10,0,0" VerticalAlignment="Top" Width="75" Foreground="White" BorderBrush="White">
                        <Button.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="Black" Offset="0"/>
                                <GradientStop Color="White" Offset="1"/>
                            </LinearGradientBrush>
                        </Button.Background>
                    </Button>
                    <DataGrid x:Name="datagrid_projekt_lista" Margin="10,60,10,10"/>
                    <Label Content="Tabela :" HorizontalAlignment="Left" Margin="10,35,0,0" VerticalAlignment="Top" Foreground="White"/>
                </Grid>
            </TabItem>
            <TabItem Header="INFO">
                <TabItem.Background>
                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                        <GradientStop Color="#FFF0F0F0" Offset="0"/>
                        <GradientStop Color="#FF424B56" Offset="1"/>
                    </LinearGradientBrush>
                </TabItem.Background>
                <Grid Background="#FF424B56">
                    <Label Content="Program oparto na silniku bazy danych SQLite - www.sqlite.org. " HorizontalAlignment="Left" Margin="8,7,0,0" VerticalAlignment="Top" Foreground="White"/>
                </Grid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>
namespace projekty
{
    class Base
    {
        // zmienna path nie jest potrzebna w zadnej z metod
        // można ją spokojnie przenieść do konstruktora jako zmienną prywatną
        // ale może się przyda więc zostaje
        private string path;
        // do połączenia wystarczy db_con ustawiony raz w konstruktorze
        private SQLiteConnection db_con;


        /// <summary>
        /// Konstruktor klasy. Pobiera ścieżkę do bazy.
        /// </summary>
        /// <param name="_path"></param>

        public Base(string _path)
        {
            this.path = _path + "\\Bazy";
            string sciezkaBaza = this.path + "\\projekty.sqlite";
            this.db_con = new SQLiteConnection($"Data Source = {sciezkaBaza}; Version = 3");
        }

        public interface IBase
        {
            bool AddBaseIfNotExist();
            int GetBaseVersion();
        }
        /// <summary>
        /// Tworzy bazę jeśli nie istnieje i tabelę projekt_lista, jesli coś się nie powiodło zwraca false 
        /// </summary>
        public bool AddBaseIfNotExist()
        {
            
            bool ok;
            try
            {
                if (!Directory.Exists(this.path))
                {
                    Directory.CreateDirectory(this.path);
                }
                this.db_con.Open();
                SQLiteCommand db_cmd = db_con.CreateCommand();
                db_cmd.CommandType = CommandType.Text;
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS projekt_lista ([Numer projektu]  INT, [Nazwa projektu]  TEXT, [Data dodania] TEXT, [Data zakończenia] TEXT, [Ścieżka] TEXT)";
                db_cmd.ExecuteNonQuery();
                db_cmd.CommandText = "CREATE TABLE IF NOT EXISTS wersja_bazy ([Numer wersji]  INT)";
                db_cmd.ExecuteNonQuery();
                this.db_con.Close();
                ok = true;                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + " 0001", "Projekty-info");
                ok = false;
            }
            return ok;                
        }

        public int GetBaseVersion()
        
        {
            int wersja = 1;               
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "select * from wersja_bazy";
            db_cmd.ExecuteNonQuery();
            var dt = new DataTable();
            SQLiteDataAdapter da = new SQLiteDataAdapter(db_cmd);
            da.Fill(dt);           
            int wierszy = dt.Rows.Count;            
            if (wierszy == 0)
            {                                
                db_cmd.CommandText = "INSERT INTO wersja_bazy VALUES ('"+ wersja +"')";
                db_cmd.ExecuteNonQuery();
                this.db_con.Close();
            }
            else
            {
                this.db_con.Close();
                DataRow dtr = dt.Rows[0];
                wersja = Convert.ToInt16(dtr[0]);
                
            }
            return wersja; // metoda zwróci wersję
        }

    }
}
namespace projekty
{
    /// <summary>
    /// Logika interakcji dla klasy MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        string path;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location));
                var baza = new Base(path);
                bool results = baza.AddBaseIfNotExist();                
                if (baza.GetBaseVersion() != 1)
                {
                    // tutaj dałbym konwerter na starej bazy na nową, ale narazie nie mamy takiego konwertera więc program tego nie zrobi
                    MessageBox.Show("Nieprawidłowa wersja bazy. Konwersja niemożliwa w tej wersji programu.Nastąpi zamknięcie programu", "Projekty-info");
                    this.Close();
                }                

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + " 0002", "Projekty-info");
                this.Close();
            }

        }        
    }
}

 

Odnośnik do komentarza
Udostępnij na innych stronach

nie powinno być string przed path?

 try
            {
                string path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location));
                var baza = new Base(path);
                bool results = baza.AddBaseIfNotExist();                
                if (baza.GetBaseVersion() != 1)
                {
                    // tutaj dałbym konwerter na starej bazy na nową, ale narazie nie mamy takiego konwertera więc program tego nie zrobi
                    MessageBox.Show("Nieprawidłowa wersja bazy. Konwersja niemożliwa w tej wersji programu.Nastąpi zamknięcie programu", "Projekty-info");
                    this.Close();
                }                

            }
Odnośnik do komentarza
Udostępnij na innych stronach

@perlon przetestowałem trochę kod i zasadniczo tak jak mówiłeś catch (Exception ex) pozostawiłem tylko w klasie MainWindow.

Teraz utworzyłem taka metodę w klasie Base

public DataTable PobierzDaneTabeli(string nazwa_tabeli)
        {
            var dt = new DataTable();
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "select * from "+ nazwa_tabeli +"";
            db_cmd.ExecuteNonQuery();
            SQLiteDataAdapter da = new SQLiteDataAdapter(db_cmd);
            da.Fill(dt);
            this.db_con.Close();
            return dt;
        }

W klasie MainWindow dodałem

public MainWindow()
        {
            InitializeComponent();
            //zamykamy pewne funkcjonalności, gdyż musielibyśmy inaczej oprogramować obiekt DataGrid, a tego nie potrafię
            datagrid_projekt_lista.CanUserAddRows = false;
            datagrid_projekt_lista.CanUserDeleteRows = false;
            datagrid_projekt_lista.IsReadOnly = true;
        }

oraz

private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                //path = (new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath;
                path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location));
                var baza = new Base(path);
                baza.AddBaseIfNotExist();
                if (baza.GetBaseVersion() != 1)
                {
                    // tutaj dałbym konwerter na starej bazy na nową, ale narazie nie mamy takiego konwertera więc program tego nie zrobi
                    MessageBox.Show("Nieprawidłowa wersja bazy. Konwersja niemożliwa w tej wersji programu.Nastąpi zamknięcie programu", "Projekty-info");
                    this.Close();
                }
                DataTable tablicaprojektow = baza.PobierzDaneTabeli("projekt_lista");
                datagrid_projekt_lista.ItemsSource = tablicaprojektow.DefaultView;
            }            
                catch (Exception ex)
            {
                MessageBox.Show(ex.Message + ". Program zostanie zamknięty.", "Projekty-info");
                this.Close();
            }       
            
        }        

Jak widać AddBaseIfNotexist() nie zwraca tak jak proponowałeś żadnej wartości

 

Edytowane przez Parikon
Odnośnik do komentarza
Udostępnij na innych stronach

22 godziny temu, Parikon napisał:

Dlaczego long a nie int? Jakie jest poważne uzasadnienie zamiany. itp. 😉

Wyszło samo, bo do odczytania wersji bazy użyłem takiego kodu :

            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandText = "SELECT MAX([Numer wersji]) FROM wersja_bazy";
            var version = db_cmd.ExecuteScalar();
            this.db_con.Close();

niestety (int)version; rzuca wyjątek : "Określone rzutowanie jest nieprawidłowe." W tym konkretnym przypadku db_cmd.ExecuteScalar() zwraca object{long}, który niestety nie daje się zrzutować na int.

Uzasadnienie: Swego czasu trochę kodowałem hobbystycznie w Clipper'ze między innymi na bazach MySQL. Został mi (może durny) nawyk który przeniosłem na C# że  do CREATE, INSERT, DELETE używam w C# metody ExecuteNonQuery (zwraca ilość przetworzonych rekordów) a do SELECT używam ExecuteScalar lub ExecuteReader (zwraca wybrane rekordy) w zależności czy mam pobrać jeden czy więcej rekordów. Uzasadnienie może słabe, ale takie mi tylko przychodzi do głowy. Prawdę mówiąc dla mnie bardziej naturalną technologią w języku obiektowym byłby dostęp do bazy za pośrednictwem ORM'a, ale nie chciałbym tego tematu tu rozwijać.

Twój kod pokazuje, że można to zrobić inaczej i myślę że nie ma o co kruszyć kopii.

 

 

Odnośnik do komentarza
Udostępnij na innych stronach

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Usuń formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.

Ładowanie