Rekomendowane odpowiedzi

Niestety ja nic tu nie pomogę.

Natomiast wracając do ramek - do klasy Base dodałem taką metodę:

public bool CzyPowtorka(string nazwa, int numerkolumny)
        {
            bool buul = false;
            DataTable dt = PobierzDaneTabeli(nazwatabeli);
            int wierszy = dt.Rows.Count;
            DataRow dtr;
            string pobor;
            int wynik = 0;

            if (wierszy > 0)
            {
                for (int i = 0; i < wierszy; i++)
                {
                    dtr = dt.Rows[i];
                    pobor = dtr[numerkolumny].ToString();
                    if (pobor == nazwa) wynik = wynik+1;
                }                
            }
            if (wynik != 0) buul = true;
            return buul;
        }

Z poziomu ZwCAD-a, dodanie dwóch rekordów o tej samej nazwie formatki powinno być niemożliwe.

Edytowane przez Parikon

Udostępnij tego posta


Odnośnik do posta
Udostępnij na innych stronach

Warunek if(wierszy > 0) i for(int = 0; i < wiersz; i++ ) są tożsame. if jest niepotrzebny, bo jeżeli wierszy == 0 to 0 < 0 = false i pętla for się nie wykona ani razu.

Na razie baza jest mikro i czas wykonania będzie nie mierzalny, ale co do zasady tego tak nie wolno robić !!! Co się stanie jak rekordów będzie 1000 000?

To powinno się załatwić :

SELECT COUNT() FROM ramki_dane WHERE format='jakis_format_z_pola_tekstowego'

Jeżeli zwróci 0 to nie ma rekordu w przeciwnym razie wiadomo. Niech się baza męczy a nie twoja aplikacja. Generalnie SELECT * FROM ... bez WHERE to bardzo zła metoda. 

1 godzinę temu, Parikon napisał:

Z poziomu ZwCAD-a, dodanie dwóch rekordów o tej samej nazwie formatki powinno być niemożliwe.

Zgadza się, ale lepiej żeby baza broniła się sama niż ma ją bronić zewnętrzna aplikacja. Wewnętrzne mechanizmy i algorytmy bazy będą zawsze lepsze niż iterowanie rekordów w aplikacji. Polecam indeks UNIQUE albo PRIMARY KEY

Edytowane przez perlon

Udostępnij tego posta


Odnośnik do posta
Udostępnij na innych stronach

Masz rację, powinno być o wiele szybciej. Zmieniłem metodę.

public bool CzyPowtorka(string nazwa)
        {
             
            bool bull = false;
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "select * from  " + nazwatabeli + " where [Format] = '" + nazwa + "'";
            db_cmd.ExecuteNonQuery();
            var dt = new DataTable();
            SQLiteDataAdapter da = new SQLiteDataAdapter(db_cmd);            
            da.Fill(dt);
            db_con.Close();

            int wierszy = dt.Rows.Count;
            if (wierszy > 0) bull = true;

            return bull;
        }

Czy istnieje w SQL taka komenda, która wstawi rekord po rekordzie, który wskażemy, a nie na końcu tabeli? Przykładowo, chcemy dodać nową formatkę A1+. Wybieramy z DataGrid wiersz i odczytujemy jego dane. Następnie wstawiamy do bazy rekord jako następny po tym zaznaczonym. Po mojemu byłoby to tak 😉 "insert po from nazwatabeli where [Format] = wybrananazwa"

Udostępnij tego posta


Odnośnik do posta
Udostępnij na innych stronach

W bazach relacyjnych zakłada się, że kolejność rekordów jest taka jak kolejność dodawania. Odpowiednie sortowanie załatwia się klauzulą ORDER BY na etapie wyciągania danych z bazy a nie w momencie wstawiania. ORDER BY załatwia że zanim baza zwróci wynik zapytania to go najpierw posortuje.

SELECT * FROM ramki_dane WHERE `jakis_filtr` ORDDER BY `Format` 

Oczywiście WHERE nie będzie jak chcesz wyciągnąć wszystkie rekordy.

Żeby było bazie lżej zakłada się na kolumny indeksy. Są one aktualizowane przy każdym INSERT, DELETE i UPDATE. Indeksów może być wiele. Baza jest inteligentna i jeżeli uzna, że przy sortowaniu warto użyć jakiegoś indeksu to go użyje. Jeżeli nie znajdzie dobrego indeksu zastosuje ogólne metody sortowania. ORDER BY może zawierać łączenia pól np.

ORDER BY `jakies_pole`+`inne_pole`

Uwaga. Zapytania realizują również operacje matematyczne więc wartości liczbowe zostaną dodane i należy kontrolować typy. Może być np wymagana konwersja pola w samej kwerendzie. Ogólna uwaga ExecuteNonQuery() stosuje się do INSERT, UPDATE i DELETE. Do SELECT powinno się użyć ExecuteReader() dla zestawów i ExecuteScalar() gdy kwerenda zwraca dokładnie jedną daną. Taką kwerendą jest np SELECT COUNT() ... Zapuść sobie takie zapytanie w DB Browser SQLita to zobaczysz że danych z bazy można wyciągać mniej i osiągnąć ten sam rezultat. Generalnie wiele rzeczy da się zrobić po stronie bazy a w programie już tylko durne wyświetlanie gotowych zestawów posortowanych, pofiltrowanych, pogrupowanych i co tam jeszcze.

Edytowane przez perlon

Udostępnij tego posta


Odnośnik do posta
Udostępnij na innych stronach

 

W uzupełnieniu:

https://pl.wikipedia.org/wiki/SQL_injection

https://www.plukasiewicz.net/Artykuly/SQLInjection_dla_poczatkujacych

Ale dla tego typu zastosowań może nie warto za bardzo się ścierać.

Moje propozycja :

        public bool CzyPowtorka(string nazwa)
        {
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "select count() from " + nazwatabeli + " where [Format] = '" + nazwa + "'";
            var result = (long)db_cmd.ExecuteScalar();
            db_con.Close();

            return result > 0;
        }

a dla pobierania danych z tabeli ramki_dane

db_cmd.CommandText = "select * from " + nazwa_tabeli + " order by format desc";

Ponadto jeszcze jedna uwaga.

DataTable dt = baza.PobierzDaneTabeli(baza.nazwatabeli);

Skoro wywołujesz metodę PobierzDaneTabeli() klasy Base to instancja baza zna pole nazwatabeli. Nie ma sensu pobieranie z instancji jakiegoś pola po to żeby przekazać je z powrotem jako argument metody tej samej instancji. 

powinno być :

DataTable dt = baza.PobierzDaneTabeli();
        public DataTable PobierzDaneTabeli1()
        {
            var dt = new DataTable();
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "select * from " + this.nazwatabeli + " order by format desc";
            db_cmd.ExecuteNonQuery();
            SQLiteDataAdapter da = new SQLiteDataAdapter(db_cmd);
            da.Fill(dt);
            this.db_con.Close();

            return dt;
        }

a nazwa tabeli skoro jest zmienną publiczną powinna być ustawiana w konstruktorze klasy. Są dwa konstruktory żeby działało po staremu w reszcie kodu.

        public Base(string _path) : this(_path, "ramki_dane")
        {
        }

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

 

Edytowane przez perlon

Udostępnij tego posta


Odnośnik do posta
Udostępnij na innych stronach

Myślę, że nie ma co paranoidalnie podchodzić do naszej bazy, gdyż użytkownik prędzej wykasuje bazę z katalogu bazy niż zastosuje odpowiednią nazwę formatki aby kwerenda zadziałała inaczej. Ale dzięki za artykuły, zawsze warto wiedzieć więcej niż mniej.  Jeśli chodzi o metodę PobierzDane... to napisałem ją tak, abym mógł ją wykorzystywać w przyszłości  odpytując różne tabelę. A jak tak tę metodę napisałem, to muszę podać nazwę tabeli. A ponieważ nie chciało mi się kopiować nazwy, to ją upubliczniłem i wybrałem jako już gotową do wyboru. Nie zastosowałem count() bo nie wiedziałem jak sprawdzić to zapytanie. Zrobiłem więc tak jak potrafię, czyli inaczej niż ty być zrobił. Teraz podałeś jak byś postąpił dalej, więc zaraz wypróbuje.

Trzeba inaczej zadać zapytanie, gdyż podane nie działa tak jak chcielibyśmy. Działa dopiero gdy tak sformułuje zapytanie.

db_cmd.CommandText = "select * from " + nazwa_tabeli + " order by [Format] desc";

 

Udostępnij tego posta


Odnośnik do posta
Udostępnij na innych stronach

Nawiasy kwadratowe są potrzebne tylko w kolumnach które maja minus bo baza próbuje wykonać operację G minus marg. W klamerkach przyjmuje całość jako identyfikator. Jak widać poniżej w innych przypadkach nawiasy nie są potrzebne. Jak widzisz w kontrolkach musiałeś już użyć podkreślenia bo minus jest niedopuszczalny. Nazwy kolumn w bazach z polskimi literami nie wyglądają dobrze. Nagłówki w gridzie możesz ustawić osobno już z śćźł jak tam chcesz ale w bazie lepiej trzymać kolumny bez polskich liter. Masz wersję kwerendy która robi update w jednym kroku. U mnie bez nawiasów działa.

        public void ZmienDaneWTabeli()
        {            
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "update " + nazwatabeli + " set " +
                "Format='" + UserControl2.nazwaformatki + "'," +
                "Wysokość='" + UserControl2.wysokosc + "'," +
                "Długość='" + UserControl2.dlugosc + "'," +
                "[G-marg]='" + UserControl2.G_marg + "'," +
                "[D-marg]='" + UserControl2.D_marg + "'," +
                "[L-marg]='" + UserControl2.L_marg + "'," +
                "[P-marg]='" + UserControl2.P_marg + "' " +
                "where Format='" + UserControl1.formatka + "'";
            db_cmd.ExecuteNonQuery();
            db_con.Close();
        }

 

Udostępnij tego posta


Odnośnik do posta
Udostępnij na innych stronach

Racja.

private string[] kolumny = { "Format","Wysokość","Długość","G-marg","D-marg","L-marg","P-marg"};

public void ZmienDaneWTabeli()
        {
            this.db_con.Open();
            SQLiteCommand db_cmd = db_con.CreateCommand();
            db_cmd.CommandType = CommandType.Text;
            db_cmd.CommandText = "update " + nazwatabeli + " set " +
                "[" + kolumny[0] + "]='" + UserControl2.nazwaformatki + "'," +
                "[" + kolumny[1] + "]='" + UserControl2.wysokosc + "'," +
                "[" + kolumny[2] + "]='" + UserControl2.dlugosc + "'," +
                "[" + kolumny[3] + "]='" + UserControl2.G_marg + "'," +
                "[" + kolumny[4] + "]='" + UserControl2.D_marg + "'," +
                "[" + kolumny[5] + "]='" + UserControl2.L_marg + "'," +
                "[" + kolumny[6] + "]='" + UserControl2.P_marg + "' " +
                "where [" + kolumny[0] + "]='" + UserControl1.formatka + "'";
            db_cmd.ExecuteNonQuery();
            db_con.Close();
        }

Pozostawiłem nawiasy kwadratowe z racji tego, że są bardziej elastyczne. Mogę zrobić tak, że:

kolumny[0] = "Formatka arkusza"

i już by się program wysypał, gdyby nie nawiasy.

Udostępnij tego posta


Odnośnik do posta
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się