Access
 sql >> Baza danych >  >> RDS >> Access

Jak program Access komunikuje się ze źródłami danych ODBC? Część 4

Co robi Access, gdy użytkownik wprowadza zmiany w danych w tabeli połączonej ODBC?

Nasza seria śledzenia ODBC jest kontynuowana, aw tym czwartym artykule wyjaśnimy, jak wstawiać i aktualizować rekord danych w zestawie rekordów, a także proces usuwania rekordu. W poprzednim artykule dowiedzieliśmy się, jak program Access radzi sobie z wypełnianiem danych ze źródeł ODBC. Widzieliśmy, że typ zestawu rekordów ma istotny wpływ na sposób, w jaki program Access będzie formułował zapytania do źródła danych ODBC. Co ważniejsze, odkryliśmy, że w przypadku zestawu rekordów typu Dynaset program Access wykonuje dodatkową pracę, aby uzyskać wszystkie informacje wymagane do wybrania pojedynczego wiersza za pomocą klucza. Będzie to miało zastosowanie w tym artykule, w którym zbadamy, jak obsługiwane są modyfikacje danych. Zaczniemy od wstawiania, co jest najbardziej skomplikowaną operacją, następnie przejdziemy do aktualizacji i wreszcie usunięcia.

Wstawianie rekordu do zestawu rekordów

Zachowanie wstawiania zestawu rekordów typu Dynaset będzie zależeć od tego, jak program Access postrzega klucze tabeli bazowej. Będą 3 różne zachowania. Pierwsze dwa dotyczą obsługi kluczy podstawowych, które są w jakiś sposób automatycznie generowane przez serwer. Drugi jest szczególnym przypadkiem pierwszego zachowania, które ma zastosowanie tylko z backendem SQL Server przy użyciu IDENTITY kolumna. Ostatni dotyczy przypadku, gdy klucze są dostarczane przez użytkownika (np. klucze naturalne w ramach wprowadzania danych). Zaczniemy od bardziej ogólnego przypadku kluczy generowanych przez serwer.

Wstawianie rekordu; tabela z kluczem podstawowym wygenerowanym przez serwer

Kiedy wstawiamy zestaw rekordów (ponownie, sposób, w jaki to robimy, za pośrednictwem interfejsu użytkownika programu Access lub VBA, nie ma znaczenia), program Access musi wykonać pewne czynności, aby dodać nowy wiersz do lokalnej pamięci podręcznej.

Należy zauważyć, że program Access ma różne zachowania wstawiania w zależności od konfiguracji klucza. W tym przypadku Cities tabela nie ma IDENTITY atrybut, ale raczej używa SEQUENCE obiekt do wygenerowania nowego klucza. Oto sformatowany śledzony SQL:

SQLExecDirect:INSERT INTO "Application"."Cities" ("CityName" ,"StateProvinceID" ,"LatestRecordedPopulation" ,"LastEditedBy") WARTOŚCI ( ? ,? ,? ,?)SQLPrepare:SELECT "CityID" ,"CityName „ , „Identyfikator województwa”, „Lokalizacja”, „Najnowsza zarejestrowana populacja”, „Ostatnio edytowane przez”, „Ważne od”, „Ważne do” FROM „Aplikacja”. „Miasta”, GDZIE „ID miasta” JEST NULL . "Miasta". "Identyfikator Miasta" Z "Aplikacji". "Miasta" WHERE "Nazwa Miasta" =? ORAZ „Identyfikator Województwa Stanu” =? ORAZ „Najnowsza zarejestrowana populacja” =? AND "LastEditedBy" =?SQLExecute:(PRZEJDŹ DO ZAKŁADKI)SQLExecute:(FETCH MULTI-ROW)
Pamiętaj, że program Access prześle tylko kolumny, które zostały faktycznie zmodyfikowane przez użytkownika. Mimo że samo zapytanie zawierało więcej kolumn, edytowaliśmy tylko 4 kolumny, więc program Access uwzględni tylko je. Zapewnia to, że program Access nie koliduje z domyślnym zachowaniem ustawionym dla innych kolumn, których użytkownik nie zmodyfikował, ponieważ program Access nie ma konkretnej wiedzy na temat obsługi tych kolumn przez źródło danych. Poza tym instrukcja insert jest prawie taka, jakiej byśmy się spodziewali.

Drugie stwierdzenie jest jednak nieco dziwne. Wybiera dla WHERE "CityID" IS NULL . Wydaje się to niemożliwe, ponieważ wiemy już, że CityID kolumna jest kluczem podstawowym i z definicji nie może mieć wartości null. Jeśli jednak spojrzysz na zrzut ekranu, nigdy nie zmieniliśmy CityID kolumna. Z punktu widzenia programu Access jest NULL . Najprawdopodobniej Access przyjmuje pesymistyczne podejście i nie zakłada, że ​​źródło danych faktycznie będzie zgodne ze standardem SQL. Jak widzieliśmy w sekcji omawiającej, w jaki sposób program Access wybiera indeks, który ma być użyty do jednoznacznej identyfikacji wiersza, może to nie być klucz podstawowy, a jedynie UNIQUE indeks, który może zezwolić na NULL . W tym mało prawdopodobnym przypadku krańcowym wykonuje zapytanie tylko po to, aby upewnić się, że źródło danych nie utworzyło nowego rekordu o tej wartości. Po sprawdzeniu, że nie zostały zwrócone żadne dane, próbuje ponownie zlokalizować rekord za pomocą następującego filtra:

GDZIE "Nazwa miasta" =? ORAZ „Identyfikator Województwa Stanu” =? ORAZ „Najnowsza zarejestrowana populacja” =? ORAZ „LastEditedBy” =?
które były tymi samymi 4 kolumnami, które użytkownik faktycznie zmodyfikował. Ponieważ istniało tylko jedno miasto o nazwie „Zeke”, otrzymaliśmy z powrotem tylko jeden rekord, a zatem program Access może następnie wypełnić lokalną pamięć podręczną nowym rekordem tymi samymi danymi, które zawiera źródło danych. Wprowadzi zmiany w innych kolumnach, ponieważ SELECT lista zawiera tylko CityID klucz, którego następnie użyje w już przygotowanym oświadczeniu, aby następnie wypełnić cały wiersz za pomocą CityID klawisz.

Wstawianie rekordu; tabela z autoinkrementacją klucza podstawowego

Co jednak, jeśli tabela pochodzi z bazy danych SQL Server i zawiera kolumnę z autoinkrementacją, taką jak IDENTITY atrybut? Access zachowuje się inaczej. Stwórzmy więc kopię Cities tabeli, ale edytuj tak, aby CityID kolumna jest teraz IDENTITY kolumna.

Zobaczmy, jak program Access sobie z tym radzi:

SQLExecDirect:INSERT INTO „Application”. „Cities” ( „CityName”, „StateProvinceID”, „LatestRecordedPopulation”, „LastEditedBy”, „ValidFrom”, „ValidTo”) WARTOŚCI ( ? ,? ,? ,? ,? ,?)SQLExecDirect:SELECT @@IDENTITYSQLExecute:(PRZEJDŹ DO ZAKŁADKI)SQLExecute:(PRZEJDŹ DO ZAKŁADKI)
Jest znacznie mniej paplaniny; po prostu robimy SELECT @@IDENTITY aby znaleźć nowo wstawioną tożsamość. Niestety nie jest to ogólne zachowanie. Na przykład MySQL obsługuje możliwość wykonania SELECT @@IDENTITY , jednak program Access nie zapewni takiego zachowania. Sterownik PostgreSQL ODBC ma tryb emulacji SQL Server w celu nakłonienia Access do wysłania @@IDENTITY do PostgreSQL, aby mógł mapować na odpowiednik serial typ danych.

Wstawianie rekordu z określoną wartością klucza podstawowego

Zróbmy trzeci eksperyment, używając tabeli z normalnym int kolumna, bez IDENTITY atrybut. Chociaż nadal będzie to klucz podstawowy w tabeli, będziemy chcieli zobaczyć, jak się zachowuje, gdy samodzielnie wstawimy klucz.

SQLExecDirect:INSERT INTO „Application”. „Cities” ( „CityID”, „CityName”, „StateProvinceID”, „LatestRecordedPopulation”, „LastEditedBy”, „ValidFrom”, „ValidTo”) WARTOŚCI ( ? ,? ,? ? Tym razem nie ma dodatkowej gimnastyki; ponieważ podaliśmy już wartość klucza podstawowego, program Access wie, że nie musi ponownie szukać wiersza; po prostu wykonuje przygotowaną instrukcję w celu ponownej synchronizacji wstawionego wiersza. Wracając do pierwotnego projektu, w którym Cities tabela użyła SEQUENCE obiekt do wygenerowania nowego klucza, możemy dodać funkcję VBA, aby pobrać nowy numer za pomocą NEXT VALUE FOR i w ten sposób proaktywnie wypełnij klucz, aby uzyskać takie zachowanie. To dokładniej przybliża sposób działania aparatu bazy danych programu Access; jak tylko zabrudzimy rekord, pobiera nowy klucz z AutoNumber typ danych, zamiast czekać, aż rekord zostanie faktycznie wstawiony. Tak więc, jeśli twoja baza danych używa SEQUENCE lub innymi sposobami tworzenia kluczy, może się opłacać udostępnienie mechanizmu proaktywnego pobierania klucza, aby pomóc w wyeliminowaniu zgadywania, które robił Access w pierwszym przykładzie.

Aktualizacja rekordu w zestawie rekordów

W przeciwieństwie do wstawek w poprzedniej sekcji, aktualizacje są stosunkowo łatwiejsze, ponieważ mamy już obecny klucz. W związku z tym Access zwykle zachowuje się bardziej prosto, jeśli chodzi o aktualizację. Istnieją dwa główne zachowania, które musimy wziąć pod uwagę podczas aktualizowania rekordu, które zależą od obecności kolumny rowversion.

Aktualizacja rekordu bez kolumny rowversion

Załóżmy, że modyfikujemy tylko jedną kolumnę. To właśnie widzimy w ODBC.

SQLExecute:(GOTO ZAKŁADKA)SQLExecDirect:UPDATE "Aplikacja"."Miasta"SET "Nazwa miasta"=?WHERE "Identyfikator miasta" =? ORAZ "Nazwa Miasta" =? ORAZ „Identyfikator Województwa Stanu” =? A „Lokalizacja” JEST NULL, A „LatestRecordedPopulation” =? ORAZ „LastEditedBy” =? ORAZ „WażnyOd” =? ORAZ „ValidTo” =?
Hmm, o co chodzi z tymi wszystkimi dodatkowymi kolumnami, których nie zmieniliśmy? Cóż, znowu Access musi przyjąć pesymistyczny pogląd. Musi założyć, że ktoś mógł zmienić dane, gdy użytkownik powoli przeszukiwał edycje. Ale skąd Access miałby wiedzieć, że ktoś inny zmienił dane na serwerze? Cóż, logicznie rzecz biorąc, jeśli wszystkie kolumny są dokładnie takie same, to powinien był zaktualizować tylko jeden wiersz, prawda? Właśnie tego szuka program Access, porównując wszystkie kolumny; aby upewnić się, że aktualizacja wpłynie tylko na dokładnie jeden wiersz. Jeśli stwierdzi, że zaktualizował więcej niż jeden wiersz lub zero wierszy, wycofuje aktualizację i zwraca błąd lub #Deleted do użytkownika.

Ale… to trochę nieefektywne, prawda? Co więcej, może to powodować problemy, jeśli istnieje logika po stronie serwera, która może zmienić wartości wprowadzane przez użytkownika. Aby to zilustrować, załóżmy, że dodajemy głupi wyzwalacz, który zmienia nazwę miasta (oczywiście tego nie zalecamy):

CREATE TRIGGER SillyTriggerON Application.Cities PO UAKTUALNIENIU ASBEGIN UPDATE Application.Cities SET CityName ='zzzzz' WHERE EXISTS ( SELECT NULL FROM wstawiony jako i WHERE Cities.CityID =i.CityID );END;
Jeśli więc spróbujemy zaktualizować wiersz, zmieniając nazwę miasta, będzie się wydawało, że się udało.

Ale jeśli potem spróbujemy go edytować ponownie, otrzymamy komunikat o błędzie z odświeżoną wiadomością:

To są dane wyjściowe z pliku sqlout.txt :

SQLExecDirect:UPDATE "Aplikacja"."Cities"SET "CityName"=?WHERE "CityID" =? ORAZ "Nazwa Miasta" =? ORAZ „Identyfikator Województwa Stanu” =? A „Lokalizacja” JEST NULL, A „LatestRecordedPopulation” =? ORAZ „LastEditedBy” =? ORAZ „WażnyOd” =? AND "ValidTo" =?SQLExecute:(PRZEJDŹ DO ZAKŁADKI)SQLExecute:(PRZEJDŹ DO ZAKŁADKI)SQLExecute:(WIELOKRZĘDOWY FETCH)SQLExecute:(WIELOWIERZOWY FETCH)
Należy pamiętać, że druga GOTO BOOKMARK i kolejne MULTI-ROW FETCH Nie wydarzyło się to, dopóki nie otrzymamy komunikatu o błędzie i go odrzuciliśmy. Powodem jest to, że gdy zabrudzimy rekord, Access wykonuje GOTO BOOKMARK , zdaj sobie sprawę, że zwrócone dane nie pasują już do tego, co mają w pamięci podręcznej, co powoduje, że otrzymujemy komunikat „Dane zostały zmienione”. Zapobiega to marnowaniu czasu na edycję rekordu, który jest skazany na niepowodzenie, ponieważ jest już nieaktualny. Pamiętaj, że program Access w końcu odkryje zmianę, jeśli damy mu wystarczająco dużo czasu na odświeżenie danych. W takim przypadku nie byłoby komunikatu o błędzie; arkusz danych zostałby po prostu zaktualizowany, aby pokazać prawidłowe dane.

Jednak w tych przypadkach Access miał odpowiedni klucz, więc nie miał problemu z odkryciem nowych danych. Ale czy to klucz jest kruchy? Jeśli wyzwalacz zmienił klucz podstawowy lub źródło danych ODBC nie reprezentowało wartości dokładnie tak, jak sądził Access, spowodowałoby to, że program Access zamalował rekord jako #Deleted ponieważ nie może wiedzieć, czy był edytowany przez serwer, czy ktoś inny, w porównaniu do tego, czy został legalnie usunięty przez kogoś innego.

Aktualizacja rekordu za pomocą kolumny rowversion

Tak czy inaczej, otrzymanie komunikatu o błędzie lub #Deleted może być dość irytujące. Istnieje jednak sposób, aby uniknąć porównywania przez program Access wszystkich kolumn. Usuńmy wyzwalacz i dodajmy nową kolumnę:

ALTER TABLE Application.CitiesADD RV rowversion NOT NULL;
Dodajemy rowversion który ma właściwość wystawiania się na ODBC jako mający SQLSpecialColumns(SQL_ROWVER) , czyli to, co program Access musi wiedzieć, że może być używany jako sposób na wersję wiersza. Zobaczmy, jak aktualizacje działają z tą zmianą.

SQLExecDirect:UPDATE „Aplikacja”. „Miasta” SET „Nazwa miasta”=? GDZIE "Identyfikator Miasta" =? AND "RV" =?SQLExecute:(PRZEJDŹ DO ZAKŁADKI)
W przeciwieństwie do poprzedniego przykładu, w którym program Access porównywał wartość w każdej kolumnie, niezależnie od tego, czy użytkownik ją edytował, czy nie, aktualizujemy rekord tylko za pomocą RV jako kryterium filtrowania. Rozumowanie jest takie, że jeśli RV nadal ma taką samą wartość jak ta, którą przekazał program Access, program Access może mieć pewność, że ten wiersz nie był edytowany przez nikogo innego, ponieważ jeśli tak, to RV jego wartość uległaby zmianie.

Oznacza to również, że jeśli wyzwalacz zmienił dane lub jeśli SQL Server i Access nie reprezentowały jednej wartości dokładnie w ten sam sposób (np. liczby zmiennoprzecinkowe), program Access nie będzie się blokował, gdy ponownie wybierze zaktualizowany wiersz i wróci z inną wartości w innych kolumnach, których użytkownicy nie edytowali.

UWAGA :Nie wszystkie produkty DBMS będą używać tych samych terminów. Jako przykład, timestamp MySQL może być używany jako rowversion do celów ODBC. Musisz zapoznać się z dokumentacją produktu, aby sprawdzić, czy obsługują one funkcję rowversion, aby można było wykorzystać to zachowanie w programie Access.

Widoki i wersja wierszy

Na widoki wpływa również obecność lub brak wersji rowversion. Załóżmy, że tworzymy widok w SQL Server z definicją:

CREATE VIEW dbo.vwCities ASSELECT CityID, CityNameFROM Application.Cities;
Aktualizacja rekordu w widoku spowoduje powrót do porównania kolumna po kolumnie, tak jakby kolumna rowversion nie istniała w tabeli:

SQLExecDirect:UPDATE "dbo". "vwCities" SET "Nazwa miasta"=? GDZIE "Identyfikator Miasta" =? ORAZ „Nazwa miasta” =?
W związku z tym, jeśli potrzebujesz zachowania aktualizacji opartego na rowversion, należy zadbać o to, aby kolumny rowversion zostały uwzględnione w widokach. W przypadku widoku, który zawiera wiele tabel w złączeniach, najlepiej jest uwzględnić przynajmniej kolumny rowversion z tabel, w których zamierzasz aktualizować. Ponieważ zazwyczaj tylko jedna tabela może być aktualizowana, w tym tylko jedna wersja wiersza może wystarczyć jako ogólna zasada.

Usuwanie rekordu w zestawie rekordów

Usunięcie rekordu zachowuje się podobnie do aktualizacji, a także użyje wersji rowversion, jeśli jest dostępna. Na stole bez rowversion otrzymujemy:

SQLExecDirect:USUŃ Z "Aplikacji". "Miasta" WHERE "CityID" =? ORAZ "Nazwa Miasta" =? ORAZ „Identyfikator Województwa Stanu” =? A „Lokalizacja” JEST NULL, A „LatestRecordedPopulation” =? ORAZ „LastEditedBy” =? ORAZ „WażnyOd” =? ORAZ „ValidTo” =?
Na stole z rowversion otrzymujemy:

SQLExecDirect:USUŃ Z "Aplikacji". "Miasta" WHERE "CityID" =? ORAZ „RV” =?
Ponownie, Access musi podchodzić pesymistycznie do usuwania, ponieważ dotyczy aktualizacji; nie chciałby usunąć wiersza, który został zmieniony przez kogoś innego. W związku z tym wykorzystuje to samo zachowanie, które widzieliśmy podczas aktualizacji, aby chronić przed wieloma użytkownikami zmieniającymi te same rekordy.

Wnioski

Dowiedzieliśmy się, jak program Access obsługuje modyfikacje danych i utrzymuje lokalną pamięć podręczną w synchronizacji ze źródłem danych ODBC. Widzieliśmy, jak pesymistyczny był Access, który był napędzany koniecznością obsługi jak największej liczby źródeł danych ODBC bez opierania się na konkretnych założeniach lub oczekiwaniach, że takie źródła danych ODBC będą obsługiwać określoną funkcję. Z tego powodu widzieliśmy, że Access będzie się zachowywał różnie w zależności od tego, jak zdefiniowano klucz dla danej tabeli połączonej ODBC. Gdybyśmy byli w stanie jawnie wstawić nowy klucz, wymagało to minimalnej pracy programu Access, aby ponownie zsynchronizować lokalną pamięć podręczną dla nowo wstawionego rekordu. Jeśli jednak pozwolimy serwerowi na wypełnienie klucza, program Access będzie musiał wykonać dodatkową pracę w tle, aby przeprowadzić ponowną synchronizację.

Widzieliśmy również, że posiadanie kolumny w tabeli, która może być używana jako wersja wiersza, może pomóc w ograniczeniu gadania między programem Access a źródłem danych ODBC podczas aktualizacji. Należy zapoznać się z dokumentacją sterownika ODBC, aby określić, czy obsługuje on wersję rowversion w warstwie ODBC, a jeśli tak, to uwzględnić taką kolumnę w tabelach lub widokach przed połączeniem z programem Access, aby czerpać korzyści z aktualizacji opartych na wersji rowversion.

Teraz wiemy, że w przypadku wszelkich aktualizacji lub usunięć program Access zawsze będzie próbował sprawdzić, czy wiersz nie został zmieniony od czasu ostatniego pobrania przez program Access, aby uniemożliwić użytkownikom wprowadzanie zmian, które mogą być nieoczekiwane. Musimy jednak wziąć pod uwagę skutki wynikające z wprowadzenia zmian w innych miejscach (np. wyzwalacz po stronie serwera, uruchomienie innego zapytania w innym połączeniu), które mogą spowodować, że Access uzna, że ​​wiersz został zmieniony i w ten sposób nie zezwoli na zmianę. Te informacje pomogą nam przeanalizować i uniknąć tworzenia sekwencji modyfikacji danych, które mogą być sprzeczne z oczekiwaniami programu Access podczas ponownej synchronizacji lokalnej pamięci podręcznej.

W następnym artykule przyjrzymy się efektom zastosowania filtrów w zestawie rekordów.

Uzyskaj pomoc od naszych ekspertów ds. dostępu już dziś. Zadzwoń do naszego zespołu pod numer 773-809-5456 lub napisz do nas na adres [email protected].


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Microsoft Access — podstawy

  2. Klasy bazowe i warianty obiektów pochodnych

  3. Sprawdź najnowsze wiadomości dotyczące Microsoft Access, w tym Access 2022!

  4. Jaka jest prawdziwa wartość wprowadzenia Microsoft Access do Twojej organizacji?

  5. Microsoft Access NIE jest martwy, podobnie jak VBA