Recommended Posts

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.

Edited by Parikon

Share this post


Link to post
Share on other sites

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

Edited by perlon

Share this post


Link to post
Share on other sites

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"

Share this post


Link to post
Share on other sites

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.

Edited by perlon

Share this post


Link to post
Share on other sites

 

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");
        }

 

Edited by perlon

Share this post


Link to post
Share on other sites

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";

 

Share this post


Link to post
Share on other sites

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();
        }

 

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
Dnia 21.02.2018 o 10:27, Parikon napisał:

Udało się wstawić moduł bazy zbrojenia w paletę ZwCAD. Niby nic a jednak cieszy.

Mógłbyś pokazać jak stworzyć własną paletę i jak wbiłeś kontrolkę WPF do takiej palety? Może jakiś link z materiałami do poczytania?

Edited by perlon

Share this post


Link to post
Share on other sites

Miło mi poinformować, że na Strona domowa PI udostępniłem program WaGaCAD PI 2019.6 w wersji testowej do użytku niekomercyjnego. Z ograniczeniem czasowym do 31 lipca 2019 i własną licencją. Chętnym zapraszam do przetestowania.

 

Edited by Parikon

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now