|
[ perun85 @ 10.01.2009. 21:07 ] @
| U jednoj maloj aplikaciji koju radim, postoji potreba za idavanjem računa.
Zbog samog načina na koji ADO.NET funkcioniše (disconnected model), u trenutku kada bih trebao da odštampam račun, ja ne znam ID koji će mu biti dodeljen u bazi.
Na koji način se može rešiti ovaj i slični problemi koje ADO.NET zbog svog načina pristupu podacima nosi sa sobom?
Unapred hvala na odgovorima.
|
[ aleksandarpopov @ 11.01.2009. 09:22 ] @
Zar ne bi trebao pre stampanja da snimis taj racun u bazu? Nakon toga vec imas ID...
[ perun85 @ 11.01.2009. 12:14 ] @
Evo da objasnim logiku koju koristim.
Za izdavanje računa koristim tri tabele, Racuni (PK idRacuna), Stavke(idStavke) i Artikli(PK(idRacuna,idStavke)).
Prilikom otvaranja forme kreiram objekat tipa RacuniRow u koji upisujem datum, vreme i druge podatke, i koji snimam u DataSet tabelu Racuni. Kada dodajem stavke u tabelu prosledjujem ArtiklRow i RacunRow objekat pored drugih podataka vezanih za datu stavku. Sve se ovo korektno snimi u DataSet bez grešaka. -> klasičan scenario izdavanja računa
Interesuje me postoji li način da se zaobiđe upisivanje u bazu pre kreiranja izveštaja (dakle sve podatka koji su mi potrebni da pročitam iz DataSeta a ne iz baze) pošto bi na taj način mogao dodatno ubrzati aplikaciju (smatram da je tako, ako grešim ispravite me)? Ukoliko gornji redosled događaja nije izvodljiv, postoji li način da mi odmah nakon upisa u tabelu Racun iz DataSet.Racun tabele bude vraćen idRacuna pod kojim je novi red snimljen?
[ MarkoBalkan @ 11.01.2009. 13:05 ] @
moj prijedlog.
stavi jedno pomoćno polje u bazu.
na pokretanje forme neka ti se izgenerira jedan broj koji će se sastojat od -> id_korisnika ili id_kase.
i možeš dodat vrijeme(sat, minuta i sekunda).
i prilikom spremanja učitaš max. broj u bazi dodaš 1 i spremiš.
ako u međuvremenu netko spremi s tim brojem, napraviš u proceduri da opet proba i tako dugo se vrti dok ne upiše.
ovo radiš preko procedure i nakon toga učitaš račun(broj i ostalo gdje je pomoćni broj jednak na formi).
to ti je cijela mudrost.
[ perun85 @ 11.01.2009. 13:51 ] @
Hvala Marko, tako cu i uraditi. Mislio sam da u samom frameworku postoji resenje ovog problema.
[ MarkoBalkan @ 11.01.2009. 15:00 ] @
a drugi prijedlog je.
kad ti se forma otvori da spremiš broj računa, a onda radiš update sa forme.
mana ovog je da ako odustaneš, onda ostane rupa, a tog ne smije biti.
[ perun85 @ 11.01.2009. 16:35 ] @
Implementiraću malo modifikovanu verziju tvog prvog predloga. Nadam se da neće to smanjiti brzinu izvršavanja aplikacije.
[ mmix @ 11.01.2009. 17:17 ] @
Sad tek vidim ovu temu.
Sto se uopste maltertirate sa time, ako je adapter dobro napravljen dobices posle update-a nazad nove ID-eve, a samu dataset schemu (pretpostavljam da ti je ID polje autoinkrement) namestis da ID polja budu seed -1 increment -1 da se osiguras da novi redovi nikad ne preklapaju i sve ti je reseno samo.
fora sa MAX+1 i optimistickim lockingom je nepotrebno spora a verovatno i neizvodljiva ako je ID autoincrement (u prevodu ako sam SQL server radi to sto ti hoces, tj. max+1, s tim sto SQL server zna koji je max bez da skenira celu tabelu)
[ perun85 @ 11.01.2009. 20:49 ] @
Upravo te vrednosti IDieva su mi i potrebne, a ne mogu da pronađem u dokumentaciji kako da ih pokupim.
Pri dodavanju novih stavki koristim metod kome prosleđujem "roditeljske" redove iz tabela Racun i Artikli, kako su seed i increment ID polja setovani od strane .Neta (koristim strongly typed DataSet) sama rutina se i pobrine da redovi u DataSet.Stavke budu referencirani na odgovarajuće redove u tabelama Racuni i Artikli.
Pogledaću još dokumentaciju, pa ću javiti šta sam uspeo da uradim.
[ mmix @ 11.01.2009. 21:09 ] @
I to si uradio kako treba (referenciranje objektima dataset u pozadini "prepeva" u referenciranje ID-em), ono sto tebi treba je dobro konfigurisan DataAdapter. Imas li ga? Kako uopste upisujes dataset u bazu? DataAdapter ima 4 CRUD komande select, insert, update i delete. AKo insert/update na kraju svog posla urade select koji vrati upravo unet/updateovan red onda ce dataadapter automatski updateovati sam dataset iz kojeg je potekla izmena/nov red. Tako se radi. Insert komanda npr treba da bude:
Code:
insert into Tabela (p1, p2) values (@p1, @p2);
select TabelaID, p1, p2 from Tabela where TabelaID = SCOPE_IDENTITY();
[ perun85 @ 11.01.2009. 21:48 ] @
Vrednosti iz neke tabele u DataSetu upisujem pozivanjem tableAdapter.Update() metoda. U principu izradu DataSeta radim u designeru, tako da i Update metode TableAdaptera radim kroz designerov wizard.
Ukoliko imas link ka dokumentaciji o ovoj temi verujem da bi mi prilicno koristio.
[ Astek @ 12.01.2009. 18:06 ] @
A ako više korisnika koristi programčić pa onda se desi da posle štampanja računa a pre snimanja računa u bazu iz bilo kog razloga padne ili program ili sistem a neznajući to drugi korisnik uradi svoj račun dobićeš dva izdata računa sa istim brojem. mislim da je bolje pre štampanja upisati račun u bazu a potom korišćenjem output parametara u SP i @@identity dobiti ID (koji mora biti autoid tj increment 1).
[ perun85 @ 12.01.2009. 20:23 ] @
Pa logika bi i isla tako.
Izvrsiti update baze koji bi vratio idRacuna u bazi.
Posto koristim DataAdapter.Update() metod za snimanje redova u bazu (zbog toga sto detektuje sve promene u okviru DataSeta i izvrsava potrebne Insert, Update i Delete queryje), da li cu u ovom slucaju morati da koristim DataAdapter.Insert() tako sto cu za svaki novi red u tabeli krekirati njegov objekat, dodati ga postojecoj DataSet tabeli i proslediti ga kao parametar DataAdapter.Insert() metodu?
[Ovu poruku je menjao perun85 dana 12.01.2009. u 21:46 GMT+1]
[ mkaras @ 13.01.2009. 14:32 ] @
Ja koristim sledeći sistem:
- Formiram tabelu u kojoj čuvam prvi sledeći broj računa.
- Pre štampe računa upisujem ga u bazu (do tada, račun se može i poništiti, menjati, brisati i ...) ali čim se štampa onda je konačan i mora se uneti u bazu
- Započnem transakciju, zaključam tabelu u kojoj čuvam sledeći broj računa, uzimam ga, upisujem u tabelu u kojoj čuvam račune, uvećam broj računa za jedan, upišem u tabelu sledećeg broja računa otključavam tu tabelu, završim transakciju.
Time postižem da niko ne može uneti dva ista broja računa, ne može se napraviti preskok broja računa, a u višekorisničkom radu zaključavanje tabele je veoma kratko i što je i po meni veoma bitno mogu da koristim bilo kakvu funkciju za promenu broja računa. Banalan primer je štampanje čekova čiji brojevi se menjaju po nekom algoritmu a ne uvećavaju se za jedan. Više puta sam pisao o tome i uvek se ponovi isto pitanje, a da ne pičam o sistemu koji traži najveći broj pa ga uvećava za jedan (veoma često u temama o access-u).
I, naravno, nisam ja izmislio ovaj sistem. Njega koriste svi oni koji koriste baze podataka koje nemaju tip podataka sa automatskim uvećanjem (AutoIncrement), a verovali ili ne ima i takvih baza podataka koje veoma lepo rade i bez toga.
[ mmix @ 13.01.2009. 16:56 ] @
Nikad mi nije bila jasna ta apsolutna opsesija kontinualnoscu ID-eva. Zasto je toliki greh preskociti broj da zbog toga pribegavate simuliranju ID-eva koje je prevazidjeno jos pre desetak godina? Najgore je sto se nista ne postize jer ste samo preneli referential integrity sa RDBMS na aplikativni nivo, svako sa SQL klijentom i loginom moze upropastiti celokupan integritet kljuceva tako sto ce da zaobidje mehanizme uspostavljene na aplikativnom nivou. I naravno da ima baza koje rade bez autoincrementa, na kraju krajeva mozes podatke da drzis i na busenim karticama.
Da ne pominjem probleme sa skalabilnoscu baze. ID je ID, njegova osnovna svrha nije nosenje korisnickih informacija vec uspostavljanje jedinstvenog nekompozitnog kljuca za optimalniju konstrukciju 3NF tabela i relacija. Kad koristis korisnicki definisan ID kao kljuc onda efektivno zakljucavas shemu baze na taj poslovni model i svaka sledeca izmena postaje nocna mora. Ako vec moras da imas neprekidnu i sekvencijalnu kontrolu nad nekim podatkom onda se to stavlja u zasebno polje cija dodela se kontrolise kroz pomenuti mehanizam sa lockovima na counter tabelu. To nece zastititi od manuelne izmene u bazi ali bar nece dovesti do referencijalnog raspada iste zato sto je neko resio da ubuduce broj racuna bude xxx/yy umesto xxxxx.
[ perun85 @ 13.01.2009. 21:44 ] @
Scenario za izdavanje racuna koji nameravam da primenim u aplikaciji je sledeci:
- pri pokretanju forme za kreiranje racuna automatski se unosi novi red u tabelu Racuni i vraca se njegov ID
- dodavanje DataSet tabeli Racuni novog reda
- kreiranje objekta pomenutog Racuna
- kreiranje objekta artikla koji se unosi u racun
- pri dodavanju svakog artikla u DataSet tabelu Stavke prosledjivanje objekta reda racuna, objekta artikla, ukupne cene i sl.
- povecavanje ukupne vrednosti kolone ukupanIznos reda u DataSet tabeli Racun
- ukoliko se kupac predomisli u vezi nekog artikla brise se iz DataSet Stavke njegov unos i ukupanIznos racuna
se smanjuje
- ukoliko odustane od celokupne kupovine brise se red tog racuna iz baze i svenjegove stavke u DataSet
- pre stampanja snimanje u bazu svih stavki ovog racuna i ukupnog iznosa, nakon cega sledi sama stampa izvestaja
Kako ja ovo posmatram bez obzira koliko korisnika da koristi sistem, ni u jednom trenutku ne bi trebalo da dodje do greske kao sto je izdavanje dva racuna sa istim IDijem. U ovom slucaju sasvim je svejedno da li ce u bazi radni brojevi racuna ici u savrsenom rastucem nizu, jedino ako to nije specijalan zahtev klijenta, jer referencijalni integritet nije narusen, tako da se slazem sa mmixom.
Citat: zaključam tabelu u kojoj čuvam sledeći broj računa
ADO.NET nema native podrsku za pessimistic concurrency. Koliko sam video na netu, postoje samo odredjeni workaround nacini da se to izvede.
[ mkaras @ 13.01.2009. 22:45 ] @
Citat: perun85: Scenario za izdavanje racuna koji nameravam da primenim u aplikaciji je sledeci:
Kako ja ovo posmatram bez obzira koliko korisnika da koristi sistem, ni u jednom trenutku ne bi trebalo da dodje do greske kao sto je izdavanje dva racuna sa istim IDijem. U ovom slucaju sasvim je svejedno da li ce u bazi radni brojevi racuna ici u savrsenom rastucem nizu, jedino ako to nije specijalan zahtev klijenta, jer referencijalni integritet nije narusen, tako da se slazem sa mmixom.
ADO.NET nema native podrsku za pessimistic concurrency. Koliko sam video na netu, postoje samo odredjeni workaround nacini da se to izvede.
Vidiš, ID i nije broj računa , broj čeka, broj transakcije, ili broj ... ID i dalje služi za vezu među tabelama i može da bude i čak i autoincrement, nebitno, sve dok je jedinstven, ali nekada brojevi koji se ispisuju na dokumentima moraju da slede neki algoritam. Već sam naveo broj čeka. Odete u banku, poručite čekove, a ono na njima neki brojevi bez veze i reda. Kako onda voditi evidenciju? Nekada ti brojevi i ne moraju da budu brojevi već bilo koja kombinacija alfanumerika formirana po nekom određenom pravilu
Citat: mmix: Nikad mi nije bila jasna ta apsolutna opsesija kontinualnoscu ID-eva. Zasto je toliki greh preskociti broj da zbog toga pribegavate simuliranju ID-eva koje je prevazidjeno jos pre desetak godina? Najgore je sto se nista ne postize jer ste samo preneli referential integrity sa RDBMS na aplikativni nivo, svako sa SQL klijentom i loginom moze upropastiti celokupan integritet kljuceva tako sto ce da zaobidje mehanizme uspostavljene na aplikativnom nivou. I naravno da ima baza koje rade bez autoincrementa, na kraju krajeva mozes podatke da drzis i na busenim karticama.
Da ne pominjem probleme sa skalabilnoscu baze. ID je ID, njegova osnovna svrha nije nosenje korisnickih informacija vec uspostavljanje jedinstvenog nekompozitnog kljuca za optimalniju konstrukciju 3NF tabela i relacija. Kad koristis korisnicki definisan ID kao kljuc onda efektivno zakljucavas shemu baze na taj poslovni model i svaka sledeca izmena postaje nocna mora. Ako vec moras da imas neprekidnu i sekvencijalnu kontrolu nad nekim podatkom onda se to stavlja u zasebno polje cija dodela se kontrolise kroz pomenuti mehanizam sa lockovima na counter tabelu. To nece zastititi od manuelne izmene u bazi ali bar nece dovesti do referencijalnog raspada iste zato sto je neko resio da ubuduce broj racuna bude xxx/yy umesto xxxxx.
Čini mi se da baš i ne razumeš to što pišeš jer pišeš o stvarima o kojima niko nije ni pričao. Ta "opsesija" je nekada srž problema i mora se ispoštovati. Dobro si rekao da osnovna svrha ID nije nošenje korisničkih informacija pa ze za takve stvari i ne koristi i niko nije rekao da mora da postoji kontinualnost ID-jeva, ali zato mora da postoji kontinualnost brojeva računa u fiskalnoj kasi, kontinualnost brojeva serije čekova koji se izdaju, kontinualnost serijskig brojeva karata za neki koncert, voz, ringišpil, ... A ako znaš da napišeš funkciju onda možeš na kartama da štampaš broj reda i sedišta, ili broj vagona, kupea i sedišta, i da širimo dalje. Postoji veoma mnogo prilika kada je taj tvoj ID nekoristan za sve osim za povezivanje tabela
[ Astek @ 13.01.2009. 23:30 ] @
Ako sam dobro razumeo Perune cini mi se da malo komplikuješ stvari. Zašto bi odmah na startu formiranja tražio ID buduceg racuna kada se može desiti da taj racun ni ne bude formiran. Moja praksa je da
1. Najpre formiram ceo racun(ukljucujuci i stavke racuna)
2. Zatim snimim racun(u tu svrhu koristim SP koja mi kao output parametar vrati ID preko @@identyti)
3. Kada imam ID stampam racun
4. I ne brisem jednom snimljeni racun nego ga storniram.
5. Koristim i transakcije da se ne desi da nesto snimi a nesto ne.
[ Pharos @ 13.01.2009. 23:44 ] @
A što za ID ne koristite GUID, a za "govoreće" šifre (broj računa) drugo polje tipa string/int?
Zar nije malo cim kada imate parent/child relacije: prvo se snimi parent, pa dobijete njegov id pa onda u svim childovima parent_id zamenite sa tim novim id-em?
A kao što mmx reče, šta kada se promeni poslovna logika pa broj računa nije više u xxx nego u xxx/yy formatu. Lakše je izmeniti podatke u jednoj nego u n tabela u bazi.
Zatim, zar nije jako loše rešenje koristiti auto increment polja u bazi?
Šta kad treba izvršiti import podataka?
just my 2 cents
[ perun85 @ 14.01.2009. 00:33 ] @
Astek, ne buduceg racuna nego onog za koga se trenutrno unose stavke u formi.
[ mmix @ 14.01.2009. 13:34 ] @
Citat: Pharos: A što za ID ne koristite GUID, a za "govoreće" šifre (broj računa) drugo polje tipa string/int?
Zatim, zar nije jako loše rešenje koristiti auto increment polja u bazi?
Ako se import radi kroz replikaciju postoje mehanizmi za sinhronizaciju kljuceva (sto je inace jos jedan razlog zasto ne koristiti ID za broj racuna). GUID to resava univerzalno ali ja npr izbegavam koriscenje GUIDa sem kad je apsolutno neophodno zbog performansi joina i svih ostalih operacija jacih od O(1). Kad poredis dva GUIDa za join poredis dva 16-bajtna bloba koji nisu prilagodjeni arhitekturi danasnjih procesora, u principu GUID kljuc ima iste performanse kao char(16) kljuc. Sa druge int kljuc je 32bita i poredjenje moze da se obavi kompletno registarski. Kad i koristim GUID to je za tabele kroz koje cetokom zivota aplikacije proci vise od 2^31 redova.
Auto increment je veoma optimizovan i skalira se lepo po svim transaction izolacijama i lock granulaciji i keygen radi direktno iz memorije servera bez potrebe za dodatnim validacijama. Zbog toga inace i nastaju rupe (ako rollbackujes transakciju ID counter se ne rollbackuje jer je sledeci kljuc mozda vec izdat drugom procesu, SQL6.5 je imao ovaj bug vracao je counter unazad na rollbacku, ali je reseno u 7.0).
Na kraju GUID nije univerzalno jedinstven, samo je statisticki veoma veoma mala sansa da se pojave duplikati.  To su nekad govorili i za JMBG
Citat: Astek: 2. Zatim snimim racun(u tu svrhu koristim SP koja mi kao output parametar vrati ID preko @@identyti)
Moja preporuka ti je da koristis SCOPE_IDENTITY() umesto @@identity. Ako neko nekad zakaci insert trigger na tvoju tabelu (npr zbog audita) i taj triger insertuje neki red negde drudge, @@identity ce se pormeniti na ID iz te druge tabele, dok ce SCOPE_IDENTITY() i dalje ostati postavljen na tvoj novi ID.
Citat: mkaras: Čini mi se da baš i ne razumeš to što pišeš jer pišeš o stvarima o kojima niko nije ni pričao. Ta "opsesija" je nekada srž problema i mora se ispoštovati. Dobro si rekao da osnovna svrha ID nije nošenje korisničkih informacija pa ze za takve stvari i ne koristi i niko nije rekao da mora da postoji kontinualnost ID-jeva, ali zato mora da postoji kontinualnost brojeva računa u fiskalnoj kasi, kontinualnost brojeva serije čekova koji se izdaju, kontinualnost serijskih brojeva karata za neki koncert, voz, ringišpil, ... A ako znaš da napišeš funkciju onda možeš na kartama da štampaš broj reda i sedišta, ili broj vagona, kupea i sedišta, i da širimo dalje. Postoji veoma mnogo prilika kada je taj tvoj ID nekoristan za sve osim za povezivanje tabela
Ta opsesija nikad nije srz problema i uvek postoji bolje resenje od koriscenja rucno generisanih kljuceva u tu svrhu i ne mora se uvek ispostovati. A i ton ti nije prilagodjen kao ni opaska, bar da ne radim consulting u bankarskom sektoru pa da ti i poverujem. Serijske brojeve na cekovima ne generise banka u konkurentskom rezimu, serijske brojeve cekova generise stampar istih (u nasem slucaju zavod za izradu novcanica), banka te cekove duzi i razduzuje svojim klijentima a po vec odstampanim serijskim brojevima. Sta vise "rupe" u brojnom sistemu cekova su relativno cesta pojava (kad banka komisijski unisti ili vrati stamparu neispravno odstampane cekove pre zaduzivanja, ti brojevi se vise ne koriste i niko nece njima biti zaduzen). Ista prica vazi i za koncertne karte i za karte za voz i za skoro sve ostale sisteme, tako da nista od ovoga nema veze sa ovom raspravom.
Za fisklani racun stvarno ne znam, ali sve i da mora da bude sekvencijalan on to mora biti na nivou fiskalne kase tako da opet nemas nikakav concurrency i ne trebaju ti nikakvi lockovi. Neverovatno je koliko aplikacija funkcionise suboptimalno zbog resavanja svih problema upotrebom pesimistickog lock-a i gde mora i gde ne mora, to sto zablokiras celu firmu dok ti odsviras svoju skrpiticu to nije vazno, radi super na testiranju. Bar da je zbog necega nego zbog generisanja kljuceva i izmisljanja tople vode.
[ mkaras @ 14.01.2009. 15:04 ] @
Citat: mmix: Ta opsesija nikad nije srz problema i uvek postoji bolje resenje od koriscenja rucno generisanih kljuceva u tu svrhu i ne mora se uvek ispostovati. A i ton ti nije prilagodjen kao ni opaska, bar da ne radim consulting u bankarskom sektoru pa da ti i poverujem. Serijske brojeve na cekovima ne generise banka u konkurentskom rezimu, serijske brojeve cekova generise stampar istih (u nasem slucaju zavod za izradu novcanica), banka te cekove duzi i razduzuje svojim klijentima a po vec odstampanim serijskim brojevima. Sta vise "rupe" u brojnom sistemu cekova su relativno cesta pojava (kad banka komisijski unisti ili vrati stamparu neispravno odstampane cekove pre zaduzivanja, ti brojevi se vise ne koriste i niko nece njima biti zaduzen). Ista prica vazi i za koncertne karte i za karte za voz i za skoro sve ostale sisteme, tako da nista od ovoga nema veze sa ovom raspravom.
Za fisklani racun stvarno ne znam, ali sve i da mora da bude sekvencijalan on to mora biti na nivou fiskalne kase tako da opet nemas nikakav concurrency i ne trebaju ti nikakvi lockovi. Neverovatno je koliko aplikacija funkcionise suboptimalno zbog resavanja svih problema upotrebom pesimistickog lock-a i gde mora i gde ne mora, to sto zablokiras celu firmu dok ti odsviras svoju skrpiticu to nije vazno, radi super na testiranju. Bar da je zbog necega nego zbog generisanja kljuceva i izmisljanja tople vode.
Ti i dalje pričaš jednu te istu priču koja nema ni malo dodira sa istinom. Niko nije rekao da se koriste ručno generisani ključevi.
Reč je samo o nekim podacima koji se štampaju na izveštajima i koji moraju da budu poređani u nekom redosledu. Ne verujem baš da organizator koncerta proglasi neke karte nevažećim zato što štampar nije štampao karte za određeni red i sedište.
A šta misliš kako štampar štampa te tvoje čekove, karte i sve ostalo? Ima samo jednu mašinu i nigde ne vodi evidenciju onoga što je štampao. Kako on generiše sve te podatke koje ispisuje.
I dalje tvrdim da površno čitaš postove jer da nije tako shvatio bi da se tabela "generisanih ključeva" zaključava na jedan veoma, veoma kratak trenutak dok se ne pokupi kluč. Poenta sistema i jeste u tome da sve vreme tabele mogu da koriste svi korisnici i da se zaključavanje vrši samo u jedom veoma kratkom trenutku kada se uzima broj "računa" jer je to jedini način da se dobije jedinstven podatak, a "rupe" se rešavaju tako što se uzimanje ključa obavlja samo u momentu upisa u bazu. Tako da to sa tvojim sviranjima skriptica i blokiranjem celog sistema nema nikakvih dodirnih tačaka. A pričao si o nekom prilagođenom tonu !?
I da ponovim još jednom, ovo o čemu pričam nisam ja izmislio (sujeta je gadna stvar) pa se time i ne hvalim. Ovaj sistem godinama primenjujem i do sada sam veoma zahvalan gospodinu Whil Hentzen-u i njegovoj knjizi Visual FoxPro 3.0 koja me je naučila mnogim stvarima. Tu su još i grupa autora Paul Litwin, Ken Getz, Mike Gunderloy sa njihovom knjigom Access 2002 za programere. I zamisli, svi oni za neke slučajeve preporučuju baš rešenje koje sam ja pokušao da približim pokretaču teme.
[ mmix @ 14.01.2009. 19:01 ] @
Citat: mkaras: Ti i dalje pričaš jednu te istu priču koja nema ni malo dodira sa istinom. Niko nije rekao da se koriste ručno generisani ključevi.
Mi smo ovde pricali o ID-u racuna, na sta si se ti nadovazeo sa citiram: " Formiram tabelu u kojoj čuvam prvi sledeći broj računa, ..., Započnem transakciju, zaključam tabelu u kojoj čuvam sledeći broj računa". Ako nisi mislio na kljuc onda si ti povrsno procitao temu.
Citat: mkaras: Reč je samo o nekim podacima koji se štampaju na izveštajima i koji moraju da budu poređani u nekom redosledu. Ne verujem baš da organizator koncerta proglasi neke karte nevažećim zato što štampar nije štampao karte za određeni red i sedište.
A šta misliš kako štampar štampa te tvoje čekove, karte i sve ostalo? Ima samo jednu mašinu i nigde ne vodi evidenciju onoga što je štampao. Kako on generiše sve te podatke koje ispisuje.
<cinizam>Da, siguran sam da organizator koncerta prodaje neispravno odstampane karte (npr one na kojim se vidi samo serijski broj) da ne bi kojim slucajem preskocio broj, a i obezbedjenju se nalozi da ljude sa takvim kartama puste na koncert pa posle svi zajedno sa mrmotom zamotaju cokoladu. A i ti stampari cekova oni isto imaju 1001og radnika koji klikcu jedno dugme na formi ceo dan i takmice se ko ce pre da dobije sledeci broj da bi na svom super stampacu odstampao cek, pa se onda posle skupe svi zajedno pa ih rucno sortiraju uz kaficu. </cinizam>
U single-user sistemima u kojima nema konkurencije za isti resurs nema ni nikakve potrebe za kontrolom iste, optimistic ili pessimistic.
Citat: mkaras: I dalje tvrdim da površno čitaš postove jer da nije tako shvatio bi da se tabela "generisanih ključeva" zaključava na jedan veoma, veoma kratak trenutak dok se ne pokupi kluč
A koliko je dug taj veoma veoma kratak trenutak? 1ms, 300ms, sekund? I koliko ce biti dug ako se u tabelu brojaca doda jos jedan brojac za neku drugu tabelu pa se insert procedura te druge tabele "posvadja" sa tvojom oko locka nad counter tabelom? Pa onda usred toga krene i batch import process? Pa na kraju promena poslovnog procesa dovede do promene te druge insert procedura koja sad prvo insertuje u prvu tabelu pa sve ovo preraste u deadlock i pukne? Naravno ne tokom testiranja posto je to nepotrebno, vec kad to sve udje u produkciju.
Nevazno je koliko je dug table X-lock, neka je i 5 nanosekundi, i to je mnogo kad nije neophodno a nije, i to je aspekt koji tebi promice. I mislim da jesam merodavan da dam sud o tome posle vise desetina aplikacija koje sam rewrite-ovao nakon sto je program poceo da posustaje sa 1000, 500 ili cak desetak korisnika zbog lose organizovanih transakcija koje se ne skaliraju lepo sa brojem korisnika; genijalni autori istih naravno nikad nisu ni probali da urade bilo kakav stress testing.
Nikad ne treba uzimati vise resursa nego sto ti je minimalno neophodno da zavrsis odredjeni zadatak bez obzira na to sta pravis i koliko trenutno korisnika to koristi.
Citat: mkaras:I da ponovim još jednom, ovo o čemu pričam nisam ja izmislio (sujeta je gadna stvar) pa se time i ne hvalim. Ovaj sistem godinama primenjujem i do sada sam veoma zahvalan gospodinu Whil Hentzen-u i njegovoj knjizi Visual FoxPro 3.0 koja me je naučila mnogim stvarima. Tu su još i grupa autora Paul Litwin, Ken Getz, Mike Gunderloy sa njihovom knjigom Access 2002 za programere. I zamisli, svi oni za neke slučajeve preporučuju baš rešenje koje sam ja pokušao da približim pokretaču teme.
No comment. Ti hoces da pricas o dobrim i losim stvarima u concurrency control mehanizmima na SQL serveru a kao teroijsku podlogu donosis FoxPro i Access? Eto perun85, batali SQL server i autoincrement, predji na FoxPro.
[ mkaras @ 14.01.2009. 20:30 ] @
Ti i dalje dokazuješ neku vajnu kompetentnost. Daj, molim te, u Pančevu, reci koja to banka ima aplikaciju sa više stotina klijenata, da ne pričam o onoj hiljadarki klijenata koju si pomenuo. I koje si ti tolike aplikacije
I dalje ne čitaš postove, nigde niko nije pomenuo SQL server osim, naravno, samo ti.
Cinizam ti nije na mestu. Bolje uzmi malo literature i pročitaj. Možda ćeš tada i saznati, ali i shvatiti zbog čega, da se jedna tabela ne koristi za više ključeva već samo za jedan jedini.
To što sam pomenuo knjige o Fox-u i Access-u to je samo zato što su mi bile pri ruci. Ali ako se malo potrudiš, nešto slično ćeš naći i u literaturi za Oracle pa čak i za MS SQL server.
[ Astek @ 14.01.2009. 21:10 ] @
mmix,
zaista nisam znao ovo za SCOPE_IDENTITY() . Blagodarim.
Ja sam takođe mislio da je ovde priča o Sql serveru.
[ perun85 @ 14.01.2009. 21:37 ] @
Ja sam zaboravio da pomenem da koristim SQL Server 2005 Express. Aplikacija koju radim nece nikada biti koristena u realnom okruzenju, radim je cisto da bih bolje upoznao mogucnosti .NETa u radu sa bazama. Iz tog razloga ne zelim da koristim workaround metode, nego samo ciste mehanizme koje pruza sam ADO.NET. Posto on nema podrsku za klasicnipessimistic concurrency od toga sam u samom startu odustao.
Licno smatram da se vicina aplikacija bez obzira na to sta rade mogu prilagoditi optimistic concurrency modelu pristupa. Odmah da priznam da ovo ne govorim iz nekog velikog iskustva, ali ukoliko je Microsoft odlucio da usvoji ovaj nacin pristupa u svojoj tehnologiji koja je uglavnom namenjena izradi poslovnih aplikacija, skoro je sigurno da se pomocu dobrog algoritma i optimistic modela moze uspesno resiti 98% scenarija u aplikacijama.
[ Pharos @ 15.01.2009. 11:43 ] @
Citat: mmix: Kad poredis dva GUIDa za join poredis dva 16-bajtna bloba koji nisu prilagodjeni arhitekturi danasnjih procesora, u principu GUID kljuc ima iste performanse kao char(16) kljuc. Sa druge int kljuc je 32bita i poredjenje moze da se obavi kompletno registarski.
Možeš li mi reći koliko ovo utiče na preformanse? Nisam imao prilike da radim sa velikim sistemima kao ti. Testirao sam sa stotinak hiljada redova podataka i performanse su gotovo identične za GUID i int. Bio bih ti veoma zahvalan da mi daš neka poređenja.
Citat: mmix: Na kraju GUID nije univerzalno jedinstven, samo je statisticki veoma veoma mala sansa da se pojave duplikati.
Da li ti se ovo ikad desilo u produkciji?
Zahvaljujem se na odgovorima
[ Djoks @ 15.01.2009. 14:18 ] @
Citat: Pharos:Možeš li mi reći koliko ovo utiče na preformanse? Nisam imao prilike da radim sa velikim sistemima kao ti. Testirao sam sa stotinak hiljada redova podataka i performanse su gotovo identične za GUID i int. Bio bih ti veoma zahvalan da mi daš neka poređenja.
http://www.informit.com/articles/printerfriendly.aspx?p=25862
Što se drugog pitanja tiče: sjećam se MS kursa o administraciji SQL Server-a 7 gdje nam je predavač (Dragoslav Ogar) rekao da je imao slučaj ponavljanja GUID-a u praksi, što mu je bilo zapanjujuće - ali tako je bilo, i to u bazi podataka o spisku birača u tadašnjoj YU.
[ mmix @ 15.01.2009. 14:57 ] @
Pretece me, ali generalno je ono sto pise u dokumentu relevantno, za jedan inner join sto smo mi testirali na 1mil redova uvezanih za 2 mil child redova kasnjenje je bilo oko 10%, s tim da je index scan imao mnogo vise read-ova za GUID nego za int (verovano zato sto manje kljuceva upadne u jedan page) pa dosta zavisi i od toga koliko je brz I/O (ipak smo mi testirali na zverini od servera sa 256Mb kesiranog RAID-a). Al mozes i sam to da testiras, milion redova se napravi ocas (samo ucini sebi uslugu i bazu kreiraj u simple recovery modu i indekse kreiraj na kraju  ). Ono sto se sigurno secam je da smo radili i testiranje za varbinary(16) i varchar(16) kljuceve i da su rezultati bili identicni kao za GUID.
Ogar je verovatno dobio duplikat zato sto je GUID bio generisan negde na masini bez mrezne kartice u to doba (dok su V1 GUIDi bili aktuelni) a kljuc bio generisan u aplikativnom nivou umesto na serveru i potrefilo se vreme. Da bi se dobio duplikat V1 GUID-a potrebno je da se dese dve stvari, da mrezne kartice na kompovima imaju isu MAC adresu (sto nije iskljuceno ako se petlja sa istim) i ako se kljuc generise istog trenutka u multi-CPU sistemu, sto je mnogo verovatniji ishod. Jednostavno ne postoji nacin da server sam sekvencijalno generise koliziju na single CPU sistemu jer je granulacija V1 GUID-a 100ns.
Meni se npr nije desilo nijednom, a najveca GUID tabela sa kojom smo radili je imala oko 20 miliona redova (od nekih 100mil koji su prosli kroz nju) i medju tih 20 mil nije bilo duplikata (doduse ne secam se koja je bila verzija GUIDa), mada i ja znam te price da se ljudi kunu da se kolizije pojavljuju vec na 200-300 hiljada redova. Jedini nacina na koji ja vidim da se ovo desi je high volume insert na multi-CPU sistemu sa V1 GUID generacijom u aplikativnom nivou. Sa aktuelnim V4 GUIDima koji su "random" sanse za koliziju su stvarno astronomske. Mislim da je ova paranoja izazvala pojavljivanje NEWSEQUENTIALID() funkcije od SQL2005.
PS: Evo cisto fore radi sam napravio GUID tabelu i upucao milion redova u nju preko NEWID() i nije bilo kolizije i svi GUIDi su V4 a pustio sam dva paralelna querya da pumpaju insert i na Core2-ci sam.
[ Djoks @ 15.01.2009. 15:37 ] @
Ako se dobro sjećam, ali bilo je poodavno - radilo se o bazi koja je objedinila nekoliko drugih baza sa spiskom birača na republičkim nivoima gdje su generisani GUID-ovi. Kada su došli do cjelokupne baze - ispostavilo se ČAK da je više GUID-ova bilo jednako...
E, sad... ne pamtim detalje, niti sam potencirao da se objasne uslovi u kojima je ova situacija nastala, ali vjerujem čovjeku 100% i zaključak je bio jasan: GUID se može ponoviti, ne samo u teoriji, već i u praksi...
[ mmix @ 15.01.2009. 16:50 ] @
Ma ne sumnjam ja da je on dobio duplikat, Ogara znam odavno i znam da sigurno ne bi izmislio takvo nesto niti je to sto je rekao za riplija. COM je stariji od masovnog koriscenja LAN-ova i nije retkost bila programer koji kreira GUID-e za COM objekte na masini bez NIC-a i duplikati CLSID/IID-eva su bili konstantan problem u to vreme i samim tim nije za neverovanje dupli GUID u SQL tabelama. Ali to je bilo nekad i to je bilo samo zbog formata V1 GUID-a koji se vise ne koristi u praksi.
Za V4 koji jeste u upotrebi danas bazna verovatnoca je 1 prema 2^122 (1.9e-37) da ces generisati isti GUID globalno. U okviru istog domena, npr tabele, cak i da ista ima milijardu redova sansa za pojavljivanje jedne jedine kolizije je i dalje za prakticnu primenu dovoljno blizu 0%. A kome je i taj rizik neprihvatljiv moze da koristi NEWSEQUENTIALID(). Tako da na stranu performance penalty upotrebe GUID-a mogucnost duplikata stvarno vise nije prepreka.
[ pl4stik @ 16.01.2009. 13:18 ] @
@perun85
Ako sam dobro skontao, pitanje je (izmedju ostalih  ) kako da xsd vrati SCOPE_IDENTITY() proveri http://forums.asp.net/t/990365.aspx.
Happy coding
P.S.
Citat: mmix: ...koji klikcu jedno dugme na formi ceo dan i takmice se ko ce pre da dobije sledeci broj da bi na svom super stampacu odstampao cek, pa se onda posle skupe svi zajedno pa ih rucno sortiraju uz kaficu..
       
Covjece, de ti to na pamet
[ perun85 @ 16.01.2009. 14:46 ] @
Hvala pl4astik, problem sa resio tako sto sam dodao query u TableAdapter koji je vezan za SP na SQL Serveru.
Odlucio sam da se drzim podalje od generisanih metoda DataSet designera (jer kako vidim problem mi pravi mod u kome se metod izvrsava ExecuteNonQuery umesto ExecuteScalar). Kao bolje resenje mi se cini upotreba SP i TableAdapter queryja. -> nadam se da sam u pravu
[ pl4stik @ 16.01.2009. 15:23 ] @
Citat: perun85: Odlucio sam da se drzim podalje od generisanih metoda DataSet designera (jer kako vidim problem mi pravi mod u kome se metod izvrsava ExecuteNonQuery umesto ExecuteScalar).
To je bilo pitanje
Citat: perun85: Kao bolje resenje mi se cini upotreba SP i TableAdapter queryja. -> nadam se da sam u pravu
Pa, naravno, ko coek
[ Igor Gajic @ 16.01.2009. 15:31 ] @
Napravio sam jedan mali programcic cisto da istestiram koliko cesto se javljaju duplikati za GUID redove:
Code:
MySqlConnectionStringBuilder mcsb = new MySqlConnectionStringBuilder();
mcsb.UserID = "root";
mcsb.Password = "";
mcsb.Server = "localhost";
MySqlConnection conn = new MySqlConnection(mcsb.ToString());
MySqlCommand cmd = new MySqlCommand("SELECT UUID();",conn);
Dictionary<string, int> NizGUID = new Dictionary<string, int>();
string guid;
try
{
if (conn.State == ConnectionState.Closed) conn.Open();
for (int i = 0; i < 1000 * 1000*10; i++)
{
guid = (string)cmd.ExecuteScalar();
if (!NizGUID.ContainsKey(guid))
NizGUID.Add(guid, 1);
else NizGUID[guid]++;
}
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (conn.State != ConnectionState.Closed) conn.Close();
}
label2.Text = NizGUID.Values.Max().ToString() ;
I na 10 miliona generisanih GUID-ova nije bilo ni jednog ponavljanja, tako da je mmix u pravu sto se tice frekvencije ponavljanja.
Koriscen Mysql Server 5.0, VS 2008, .NET 3.5.
[ Djoks @ 16.01.2009. 18:34 ] @
Ne može se tako generisati duplikat GUID-a ni da je izvršena simulacija unosa 100 milijardi redova u tabelu. ;)
Problem sa dupliranjem GUID-a koji sam ranije naveo - dogodio se u sasvim drugačijim okolnostima i taj problem je, tokom godina, gotovo definitivno prevaziđen kao što pokazuju reference na Web-u. :)
[ perun85 @ 16.01.2009. 19:51 ] @
Pl4astik, hvala na podrsci  .
[ mmix @ 16.01.2009. 20:14 ] @
Citat: pl4stik: @perun85
Ako sam dobro skontao, pitanje je (izmedju ostalih  ) kako da xsd vrati SCOPE_IDENTITY() proveri http://forums.asp.net/t/990365.aspx.
Happy coding
Citat: perun85: Hvala pl4astik, problem sa resio tako sto sam dodao query u TableAdapter koji je vezan za SP na SQL Serveru.
Odlucio sam da se drzim podalje od generisanih metoda DataSet designera (jer kako vidim problem mi pravi mod u kome se metod izvrsava ExecuteNonQuery umesto ExecuteScalar). Kao bolje resenje mi se cini upotreba SP i TableAdapter queryja. -> nadam se da sam u pravu
Necu da zapocinjem raspravu oko SP vs. generated script, oba imaju pro i contra, ali je ona tema na asp.net forumu losa jer i generated skripte rade veoma dobro isti posao, a momci su se nalupali posteno pokusavajuci da rese problem koji ne postoji. Razlog iz kojeg u designer.cs vidis ExecuteNonQuery je zato sto ta Insert metoda nije predvidjena za operacije nad DataSet instancama, to je tzv. DirectDB metoda koja omogucava upisivanje reda u bazu zaobilazeci DataSet.
Ako koristis DataSet i za sinhronizaciju dataset-a sa tabelom u bazi koristis TableAdapter.Update() metod (kako bill gates zapoveda  ) radice kako treba, tj npr SqlDataAdapter.Update ce za svaki poziv Insert komande koji vrati red zameniti red iz dataset-a pristiglim redom (i samim tim cete dobiti novi kljuc) i taj kod ni ne mozes da vidis u designer.cs fajlu jer tamo i nije. Kao primer attachovan je mini projekat u kojem je to realizovano u konzolnoj aplikaciji, doda se red, pozove se update adaptera i ispise se novopristigli ID koji je u bazi. Kaci se na lokalnu bazu (connection string je u app.config) i u bazi vam treba sledeca tabela:
Code: CREATE TABLE [dbo].[MojaTabela](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Data1] [nchar](10) NULL,
CONSTRAINT [PK_MojaTabela] PRIMARY KEY CLUSTERED
(
[ID] ASC
))
[ perun85 @ 17.01.2009. 11:27 ] @
U tom slucaju samo sacuvamo indexe svih redova koje smo uneli u niz, kako bi naknadno mogli da pristupimo ID svojstvu svakog reda.
[ pl4stik @ 17.01.2009. 20:09 ] @
Ma oni ih vec imaju nego u tim njihovim arhitekturama pretaraga mnogo traje (valjda)...
@mmix
Nista od ovoga sto si napisao nisam znao i sad znam, a kod josh desifrujem  Thanks man
[ mmix @ 17.01.2009. 21:25 ] @
Vazne tacke u kodu su ti main() metod u program.cs i insertCommand u table adapteru, ako ti to pomaze sa desifrovanjem. Najbolje da single-stepujes kroz main i da za svaki korak pogledas kako izgleda tabela u dataset-u i videces da posle update red ima novi realni kljuc.
[ pl4stik @ 18.01.2009. 09:02 ] @
Samo za cas da pitam i necu vise da obnavljam temu
C# je ok to nije problem, nego jel mozes malo da prokomentarishesh ovaj SQL ... ako imash vremena, ako ne nema veze, iskopace njega Billi 
[ mmix @ 18.01.2009. 09:44 ] @
SQL kreira tabelu u bazi po tvom izboru, a ta tabela se koristi u dataset-u u primeru (samo ne zaboravi da promenis connection string u app.config), ovako mi je bilo najjednostavnije da vam prenesem primer (bolje nego da sam kacio mdf :))
Copyright (C) 2001-2025 by www.elitesecurity.org. All rights reserved.
|