C# - Baza danych MSSQL - aktualizacja danych

0

Witam!

Robię program oparty na bazie danych ms-sql. Użytkownik może wprowadzać rekordy do bazy. Są to dane książek, użytkownik może też rezerwować książki, czyli modyfikować bazę.

Umieściłem w programie button, który na początku programu wczytuje dane z bazy i wypełnia nimi DataGridView. Chciałbym, żeby po wprowadzeniu zmian do bazy i kliknięciu tego przycisku jeszcze raz, dane Od razu załadowały się ponownie do dgv. Próbowałem to zrobić z kilkoma przykładami z msdn oraz znalezionymi na forum, ale niestety nic mi nie pomogło. Teraz żeby pokazać zaktualizowane dane, trzeba wyjść z programu i włączyć go jeszcze raz. Jest na to jakiś sposób?

KOD

         private void AktualizujBtn_Click(object sender, EventArgs e)
        {
            ksiazkiTableAdapter.Fill(dataset.Ksiazki);
        }

Ten kod wygenerował mi się automatycznie po podłączeniu datagridview do źródła danych.

I przy okazji, mam też mały problem. Dodałem do bazy kilka rekordów jako testy. Potem usunąłem je ręcznie z bazy w eksploratorze tablic - Show table data - lecz jak teraz dodam nowy rekord to automatycznie zwiększane ID pokazuje, że usunięte rekordy jednak jakby jeszcze w bazie były.

Przykład :
Dodałem na pozycje 21 rekord 'test', 20 pierwszych pozycji to dane o książkach. Następnie ten rekord 21 usunąłem, lecz po zrobieniu kolejnego testu wyświetliło mi się 20 tych pierwszych pozycji i zamiast teraz ID 21 pokazało mi ID 22, a całego rekordu 21 wcale nie pokazało...

0
l4n10 napisał(a):

I przy okazji, mam też mały problem. Dodałem do bazy kilka rekordów jako testy. Potem usunąłem je ręcznie z bazy w eksploratorze tablic - Show table data - lecz jak teraz dodam nowy rekord to automatycznie zwiększane ID pokazuje, że usunięte rekordy jednak jakby jeszcze w bazie były.

Przykład :
Dodałem na pozycje 21 rekord 'test', 20 pierwszych pozycji to dane o książkach. Następnie ten rekord 21 usunąłem, lecz po zrobieniu kolejnego testu wyświetliło mi się 20 tych pierwszych pozycji i zamiast teraz ID 21 pokazało mi ID 22, a całego rekordu 21 wcale nie pokazało...

Przecież usunąłeś rekord o ID 21, więc jakim cudem miałoby go pokazać? ;] Jakim cudem z tego, że autoinkrementowane ID się zwiększyło, wywnioskowałeś że jakieś dane są jeszcze w bazie?

0

najprościej po dodaniu nowego rekordu usuń całą zawartość tabelki i załaduj jeszcze raz. Co do SQL i numery id radzę przeczytać jakiś artykuł jak to dział (auto numeracja)

0

Spodziewałem się że będzie to mało zrozumiałe :)
Usunąłem go, ale autoinkrementowane ID omija ID o numerze 21, tak jakby coś tam dalej było, lub po prostu tak to działa.
Zapomniałem dodać że w bazach danych grzebie dopiero od tygodnia, wcześniej nie miałem z tym do czynienia :)

Wygląda to tak :
user image

1

Po usunięciu rekordu wskaźnik IDENTITY nie zmniejsza swojej wartości. Dzieje się tak dlatego, że pole, które przechowuje wartość IDENTITY może być powiązane relacją z inną tabelą w bazie danych. Jeżeli zmienimy tę wartość to posypie się relacja i dane mogą być niespójne (Jeżeli w ogóle używamy takich rzeczy jak klucze główne i obce, bo może istnieć baza danych, w której w ogóle nie używa się takich rzeczy, a zależności są zachowane np. gdzieś na poziomie aplikacji dostępowej).

Oczywiście można to wymusić poprzez wpisanie:

DBCC CHECKIDENT('tableName', RESEED, 0)
0

Nic tam nie ma. Dodajesz nowy rekord i on otrzymuje id większe o 1 od poprzedniego, nie ważne czy poprzedni rekord istnieje czy został usunięty.

0

Dzięki grzesiek za wytłumaczenie, teraz wszystko jasne :)

A macie jakiś pomysł co zrobić z tą aktualizacją? Próbowałem metod dataadapter.Update na różne sposoby, ale nic nie skutkuje..

1

Najprościej zrobić to co napisał @piotr91 czyli wywalić wszystko z tabeli i wpisać dane jeszcze raz, z tym że przed wpisaniem danych zresetować licznik IDENTITY. Ale... co jeśli będziesz miał 15 tyś. takich rekordów?

Ja robię w ten sposób w aplikacjach MVVM, że wartości IDENTITY nie ruszam natomiast mam w widoku coś takiego jak Lp. np:

private void wczytajListeZapotrzebowan(List<List<string>> wyn) {
    if (wyn != null) {
		this._listaZap = new ObservableCollection<ZapotrzebowanieModel>();
		for (int i = 0; i < wyn.Count; i++) {
			this._listaZap.Add(new ZapotrzebowanieModel {
				lp = (i + 1).ToString(),  // Lp. zostaje wyświetlone w aplikacji;
				id = wyn[i][0],             // id jest zapamiętywane w programie do późniejszego wykorzystania;
				nazwa = wyn[i][1],
				data = wyn[i][2],
			});
		}
    }
    else Wiadomosci.utrataPolaczeniaSQL();
}

List<List<string>> wyn - to lista wyników uzyskana poprzez wywołanie selecta z bazy danych. Lista jest dwuwymiarowa, ponieważ pierwszy wymiar reprezentuje rekord uzyskany w zapytaniu, a drugi wymiar reprezentuje konkretną wartość kolumny np 'data'.

Dzięki temu kodowi zawsze będziesz miał rekordy po kolei w widoku w aplikacji, mimo że w bazie danych wartości ID będą nieciągłe.

0
l4n10 napisał(a):

Dzięki grzesiek za wytłumaczenie, teraz wszystko jasne :)

A macie jakiś pomysł co zrobić z tą aktualizacją? Próbowałem metod dataadapter.Update na różne sposoby, ale nic nie skutkuje..

Nie napisałeś o jaki model dostępu do bazy chodzi. W bezpołączeniowym operujesz na lokalnej kopii bazy i dopóki nie zcommitujesz zmian to są one niejako "wirtualne" w kopii lokalnej. Tu sobie możesz mieszać danym do woli. Ten model jednak o ile się orientuję nie nadaje się gdy źródło danych jest kwerendą z joinami różnych tabel. Wtedy wypada mieć model połączeniowy i każda aktualizacja bazy musi nieść za sobą commity konkretnych danych i refresz zapytania SQL oraz wczytanie całego kompletu danych do grida. Dlaczego? Ano np. jeżeli zmianie uległo nazwisko z A na Z to zmienia się porządek wyświetlania (lokalizacja) wszystkich nazwisk w wyniku zapytania i trzeba je wszystkie wyświetlić od nowa w nowym porządku. To tyle teorii ale w praktyce nie pomogę bo sam jestem na początku nauki C# i możliwe że jestem w błędzie ;-)

0

Przepraszam za opóźnienia. Problem rozwiązany - wystarczyło napisać prostą metodę
Załączam kod, może komuś w przyszłości się przyda.
Pozdrawiam i dziękuje za pomoc :)

 public DataTable Fill(string sql)
        {
            DataTable dt = null;
            SqlConnection connect = null;
            SqlDataAdapter da = null;
           
            connect = GetConnection();
            da = new SqlDataAdapter(new SqlCommand(sql, connect));
            dt = new DataTable();

            connect.Open();
            da.Fill(dt);

            return dt;        
        }
// i użycie metody przy kliknięciu buttona
            dgv.DataSource = Fill("SELECT * FROM Ksiazki");

1 użytkowników online, w tym zalogowanych: 0, gości: 1