

C# Dataset bez DB
Zdravim, delam C# aplikaci, ktera neni primo spojena s DB, ale komunikuje s ni pres webserver a vymena dat probiha v JSONu. Chci v aplikaci ke sprave dat vyuzivat dataset. Uz jej umim rucne naplnit vcetne tabulek a dat.
Nyni bych ale potreboval trosku vysvetlit, jak se s datasetem (bez primo pripojene db) pracuje. A vubec - obecne. Jak nyni vlozit novy zaznam? Nejprve do db a pak do datasetu? Nebo vkladat nejdrive jen do datasetu a pak zmeny promitnout do db (jak?)? Jak mazani a editace zaznamu v datasetu a opet promitnuti do DB?
Jak je to treba s inkrementaci ID, kdyz bych nejdrive vkladal do datasetu a az pak nejak promital do DB?
Diky za pomoc.
Keď používaš DataSet, tak všetky zmeny ulož vždy najprv do DataSetu a až potom do databázy. Pretože ak budeš robiť niektoré zmeny priamo do databázy, tak skôr či neskôr narazíš na situáciu, kedy ti rozdiel medzi databázou a odpojenými dátami v DataSete spôsobí problém, pre ktorý nebude existovať "správne riešenie".
Uloženie zmien v DataSete do databázy sa robí pomocou DbDataAdapteru (pre MS SQL SqlDataAdapter). Na úplne jednoduché veci môžeš použiť DbCommandBuilder (pre MS SQL SqlCommandBuilder), to ale neodporúčam.
Nemusíš vždy ukladať všetky zmeny v DataSete - máš tam aj možnosť uložiť len vybrané riadky. Takže ak by si mal nutkanie spraviť nejakú zmenu priamo do databázy, tak môžeš zmenu zapísať do DataSetu a následne zmenené riadky do databázy. Nenapadá mi síce žiaden praktický príklad, kedy by si to takto chcel robiť, ale dá sa to.
Čo sa týka návrhu tabuliek v databáze, tak je vhodné mať v každej tabuľke stĺpec s verziou riadka (prípadne s časom poslednej úpravy), pomocou ktorého budeš vedieť, či náhodou nedošlo v upravovanom riadku medzitým ku nejakej zmene, o ktorej tvoja aplikácia nevie (optimistické zamykanie) - viď DBConcurrencyException.
Pre tabuľky, ktoré majú stĺpce s automatickým ID (ktoré je od 1 vyššie), si v DataSete nastav AutoIncrement tak, aby AutoIncrementSeed a AutoIncrementStep boli rovné -1. Nové riadky tak budú mať v DataSete záporný identifikátor. Skutočný identifikátor im prideľ až pri zápise do databázy cez adaptér (buď nastav InsertCommand, alebo si vytvor vlastný DataAdapter).
Problémy, na ktoré narazíš pri trochu zložitejších databázových schémach, sú v princípe tri a všetky súvisia s automatickými identifikátormi a cudzími kľúčmi:
1. V DataSete musíš mať nastavené správne cudzie kľúče tak, aby sa ti nový identifikátor po vložení riadka premietol do riadkov, ktoré naň odkazujú cez cudzí kľúč.
2. Zmeny v DataSete musíš ukladať v správnom poradí, pretože nie je možné vložiť riadok, ktorý sa odkazuje na iný ešte nevložený riadok.
3. Musíš počítať s tým, že budeš chcieť vymazať riadok, ktorý sa v databáze vymazal automaticky kvôli kaskádovému mazaniu.
Prvým dvom problémom sa môžeš vyhnuť tak, že po každom vložení/vymazaní riadku uložíš zmeny hneď aj do databázy, čo ale nie je vždy tak celkom možné.
Ako človek, ktorý si s DataSetmi užil svoje, ti radím sa im úplne vyhnúť, pokiaľ nemáš pre ich použitie nejaký pádny dôvod.
Ale ten DataAdapter nemohu použít, když to nemám přímo spojené s DB, ne? Já ta data stahuju v JSONu a pak konvertuju do Listů...
Nemám pro to důvod, proto se ptám, jakým směrem se vydat a jaké nástroje použít. Jsem docela překvapenej, že ten DataSet nedoporučujete, myslel jsem, že to hodně usnadní práci.
Pokud bych neměl dataset použít - jak stavět ten objektový model? Mít nějaký svůj DataProvider, kde by byly reference na nějaké xxxProvidery pro každou třídu, která by poskytovala metody pro práci s objekty třídy xxx? Každý tento provider by měl nějaký Dictionary nebo Listy?
Ako chceš ukladať dáta do databázy, keď nemáš ku nej pripojenie? A na čo ti je potom vôbec DataSet? Ktorú časť toho celého vlastne implementuješ - server, klient alebo obidve? Klient je čo presne: WPF, Windows Forms alebo niečo iné?
Ty nevieš, ako má vyzerať tvoj objektový model? Nevieš, ako načítať údaje z databázy do objektu? Alebo ako ich uložiť? Alebo na čo sa vlastne pýtaš?
Ťažko radiť nejakú architektúru pre tvoju aplikáciu, keď ani nevieme, čo má robiť.
V úvodu jsem psal, že před databází je webový server a databáze není veřejně přístupná. Proto posílám klasický sql dotazy v url na web server a ten mi v JSONu vždy pošle odpověď (data). Je to klientská aplikace ve windows forms. Vím jak načítat, vím jak ukládat, funguje mi to. Jenom to chci uvnitř té aplikace nějak poskládat, aby se s tím dobře pracovalo, aby se k datům dalo rozumně přistupovat a aby s nima byla jednoduchá manipulace. Četl jsem, že dataset, jako obraz databáze, se dá použít i bez přímého připojení k DB, že se dají datatable vytvořit manuálně a data do nich vložit. Proto bylo mým původním dotazem, jak dataset potom ovládat, když není přímo spojenej s databází.
Pak jste ale řekli, že je lepší nějaký objektový model. Mě zajímá, jak teda (a kam) data po stažení z db ukládat, jak k nim přistupovat, když v aplikaci je 15 tříd, které na sobě nějakým způsobem závisí a jak původně dataset využít, aby jejich správa v aplikaci byla co nejjednodušší...
To jsem potřeboval.
Objektový model je právě těch tvých 15 tříd (a jejich vazby mezi nimi).
To vím, ale jak to mít uložené v aplikaci (ty konkrétní objekty)? V jakých třídách? V Listech? V Dictionary? Jedna třída s 15ti Dictionary když mám 15 tříd (když to přeženu)? Jak se na to dotazovat?
V tom, co více vyhovuje tvým potřebám. Někdy stačí List, někdy je vhodnější Dictionary. I způsob dotazování záleží na tvých potřebách. Pokud použiješ Dictionary, tak se můžeš dotazovat přes klíč. Pro složitější dotazy můžeš použít LINQ, pro ještě složitější si prostě napíšeš algoritmus...
Ptáš se moc obecně, ale přitom očekáváš konkrétní odpovědi.
Asi bych se přikláněl k Dictionary, přijde mi s ním lepší práce přesně právě kvůli klíči.
Já právě ani nevím jak se pořádně ptát, je to fakt obecný. Nevím, jak se "v praxi" tyhle věci řeší a proto potřebuju nějaký odpovědi (byť nejprve na hloupé otázky).
Jenže v praxi se to řeší právě podle toho, co je potřeba. Co může být v některých případech dobré řešení, v jiném může být zase docela nevhodné.
Áno, pred databázou je webový server. Ale ten akože nerobí nič iné, len poskytuje prístup k databáze? Dokonca cez SQL priamo v URL adrese? To nie je dobre.
DataSet sa dá posielať zo servera na klienta a naopak. Ide o odpojené dáta, môžeš ich posielať hocikam a keď sa ti potom vrátia, tak ich vieš jednoducho uložiť do databázy. Nad použitím DataSetu by som ale začal teoreticky uvažovať až v prípade, že by tie dáta mali byť odpojené od databázy dlhší čas - dovtedy máš kopec iných vhodnejších možností.
Vo všeobecnosti server nebýva len taký hlúpy poskytovateľ dát, ako ho máš teraz. Obyčajne to v tvojom prípade (tučný klient) funguje tak, že server poskytuje služby, ktoré klient volá. Takže klient si vypýta nejaké informácie a server mu ich poskytne - klient si pýta od servera informácie spôsobom "daj mi detail klienta spolu s jeho objednávkami", nie že "selektni mi takéto riadky". A server mu ich poskytne ako objekty, pričom ti môže byť v podstate jedno, či to ide cez JSON alebo SOAP - podstatné je, že stále pracuješ so svojimi objektami, nepotrebuješ na to žiaden DataSet. Následne klient povie napríklad, že pridaj tomuto klientovi takúto objednávku, t.j. pošleš na server objekt typu objednávka a server ho uloží do databázy - opäť nepotrebuješ žiaden DataSet.
To, že kde si držíš dáta (objekty) na strane klienta, závisí len a len od toho, čo s tými dátami potrebuješ robiť. Zjednodušene povedané, ak ich potrebuješ zobrazovať len na jednej obrazovke, tak si ich pamätáš len pre tú jednu obrazovku. Ak ich potrebuješ mať v pamäti neustále, tak si ich pamätáš v tej svojej aplikácii. Nepotrebuješ na to nič ďalšie typu DataSet.
V URL je posílán i hash klíče, který zná jen klient a ten web server, takže si jen tak někdo nemůže data získat ani jinak s nimi manipulovat.
To nebudou odpojený delší čas, k tomu není důvod.
To jak jsi psal, že server je v tomhle případě hloupý, ano je. Původně to bylo přístupné přímo k DB, ale kvůli bezpečnosti a migraci na jinou DB, se to postavilo jak je to teď. A jelikož aplikace byla postavená, že posílala sql dotazy přímo na DB tak aby se musela co nejmíň modifikovat, posílají se pořád stejný dotazy akorát v url s přidaným hashem a výsledek z jsonu se zpracuje. To byla jediná dočasná modifikace, která musela být provedena, aby to fungovalo.
Právě proto jsem to teď chtěl nějak vyřešit...
Pokud je ten klíč posílaný v URL, tak si ho může zjistit naprosto kdokoliv, kdo je na cestě mezi tebou a tím serverem.
Je posilany hash, ale ted mi doslo, ze je to taky spatne, ze ten, kdo to odposlechne sice nemuze vytvorit svuj dotaz, ale muze opakovane posilat ten odposlechnutej dotaz porad....
Jak tohle resit? Aby se dalo indetifikovat, ze to opravdu poslal ten klient? :/
No tak minimálně používat šifrované spojení a hash neposílat v URL ale v hlavičce requestu. Nastuduj si něco o tom, jak funguje HTTP Session.
Aby to nemohol odpočuť, tak sa používa HTTPS. Pri tučnom klientovi sa zvykne predpokladať, že je nainštalovaný na bezpečnom počítači (kde je používateľ prihlásený do domény). Autentifikácia klienta potom postačuje aj cez meno/heslo, ale keď chceš, tak môžeš použiť Kerberos, klientské certifikáty, whatever - všetko závisí od prostredia, v akom má aplikácia fungovať.
To znie skoro až hrôzostrašne. Z pôvodnej otázky som mal pocit, že vytváraš novú aplikáciu, takže toto trochu mení situáciu. K bezpečnosti sa radšej vyjadrovať nebudem. Nie je mi jasné, či aplikácia v súčasnom stave funguje - hlavne či dokáže do databázy aj zapisovať.
Pôvodná aplikácia sa teda pripájala priamo na databázu. Obvykle zvykne mať aplikácia dátovú vrstvu (DAL), v ktorej sa rieši čítanie a zápis do databázy. Toto je vrstva, ktorá poskytuje biznis vrstve metódy typu "daj mi detail klienta spolu s jeho objednávkami". Pri prerábaní pôvodnej aplikácie na aplikáciu typu klient-server, s ohľadom na to aby sa čo najmenej upravovala, by sa mala dátová vrstva umiestniť na stranu servera a biznis vrstva na stranu klienta.
Súčasný spôsob rozdelenia, kedy je webový server v podstate len proxy medzi klientom a databázou, je veľmi neefektívny a aplikácia bude (resp. je) pomalá. Normálny spôsob je vytvoriť si služby, ktoré vrátia na klienta objekty/zoznam objektov - pozri sa na WCF. To, čo s tými objektami spravíš na strane klienta, závisí len a len od toho, čo potrebuješ - kľudne si môžeš zoznam vrátených objektov uložiť do slovníka, skrátka hocičo. Pri ukladaní potom zavoláš ďalšiu službu servera a ten zapíše objekt do databázy - použil by som LINQ to SQL.
Jak ale takove sluzby provest pouze za pomoci web serveru? Stejne to nejak budu muset posilat v url... Nebo?
Pozri si WCF. Žiadne dáta sa v URL neposielajú, všetko ide v tele požiadavky/odpovede.
Fajn, jdu se na to podivat, diky.