|
[ Shadowed @ 24.04.2008. 21:32 ] @
| Znam da sve ovo postoji u dokumentaciji. Medjutim, treba mi brzo pa mi je velika usteda u vremenu ako dobijem odgovore dok radim drugi deo posla. A pretpostvaljam da ce i drugima koristiti isti odgovori.
Elem, imam projekat koji trebam brzo da uradim. Nije nesto komplikovan, ali je vreme kljucna stvar. Zbog toga sam hteo koristiti linq to sql jer bi mi pola vremena oduzelo prevljenje klasa i metoda za citanje upis istih iz/u bazu. Ali je linq dosta nov za mene.
Nakon sto napravim bazu, mogu u O/R Designer-u prevuci tabele i dobiti klase. Znam i kako da prosirim klase preko parcijalnih klasa. Medjutim, (za sada) bi mi trebao neki jednostavan primer kako da ucitam podatak iz baze u objekat, imenim i snimim. Takodje, kreiranje novog objekta i upis u bazu.
Evo za jednostavan primer baze gde postoje tabele Adrese (sa kolonama ID (p.k.), ulica, gradID) i Gradovi (ID(p.k.), ImeGrada). Naravno, Adrese.gradiD je povezano sa Gradovi.ID. |
[ 01011011 @ 24.04.2008. 21:52 ] @
Ako vec imas tight deadline i moras da zavrsis to na vrijeme, nemoj pokusavati da ucis novu tehnologiju. Ono sto mozes da odradis sa Linq je slicno kao sto bi uradio kad bi generisao code iz baze podataka. Ja bih ti preporucio da vidis alatku koja se zove CodeSmith, ako je vec nisi koristio i da ti napravi na brzinu sve klase koje su ti potrebne tako da onda ti ostaje samo da zavrsis custom dio posla. CodeSMITH je dzabe za 30 dana, a ako ti treba za duze, vjerovatno se i to moze naci negdje na netu. Linq nije tezak za nauciti, jednostavno se nakaci na bazu i napravi "entiites" u tvom kodu koje ti ne vidis ali posto koristis linq on moze da ih vidi. CodeSmith ce ti uraditi isto, samo sto ces imati kao i prije code u svojim klasama.
NAdam se da ovo pomaze, a ako si bas zapeo za Linq, mogu ti postaviti link za dzabe knjigu koju je MS postavio za download.
[ Shadowed @ 25.04.2008. 00:15 ] @
Vec sam skinuo tu knjigu ranije, nasao sam primer koji mi pomaze, ali sam batalio linq iz drugih razloga - ne znam da li cu na hosting-u imati to, a malo je specificna situacija, pa ne znam da li cu moci da biram hosting.
To inace radim u php-u, ali sam poshizeo i sad van posla hocu da uradim u .net-u i da im dam gotovo :)
Taj CodeSmith cu pogledati neki drugi put. Tnx.
[ Djoks @ 25.04.2008. 02:27 ] @
Ja bih UPRAVO preporučio LINQ koji može biti kompleksan onoliko koliko ti želiš.
Elem, pitanje je kako si navikao da barataš sa podacima? Da li preko BindingSource-a, BindingNavigator-a i DataSet-a?
U svakom slučaju - što se baratanja sa podacima tiče - u par linija s' obzirom da je kasno, pa možemo nastaviti sjutra. Recimo da imamo formu i negdje u vrhu deklarišemo i instanciramo objekat:
Code:
Private DB As New AdresarDBDataContext(My.Settings.AdresarConnString)
uz pretpostavku da se u My.Settings.AdresarConnString nalazi naš string konekcije. Sada na nivou forme možemo koristiti data-kontekst baze gdje želimo. Savjetujem ti da, dok testiraš LINQ - prije baratanja sa DB objektom, koristiš osobinu log-ovanja aktivnosti data konteksta u konzolni Output prozor. Ovo ćeš postići instrukcijom:
Code:
DB.Log = Console.Out
Tako ćeš jasno moći da vidiš koje SQL upite pokreće LINQ data kontekst pri baratanju sa podacima.
Elem... Treba da dodamo podatke u bazu? Radimo sa objektima:
Code:
DB.Grads.InsertOnSubmit(New Grad With {.NazivGrada = "Beograd"})
DB.Grads.InsertOnSubmit(New Grad With {.NazivGrada = "Novi Sad"})
DB.Grads.InsertOnSubmit(New Grad With {.NazivGrada = "Kragujevac"})
DB.SubmitChanges()
to je sve što se tiče dodavanja novih podataka u bazu. Može, naravno i staromodnije:
Code:
Dim objekat As New Grad
objekat.NazivGrada = "Beograd"
DB.Grads.InsertOnSubmit(objekat)
Može i drugačije, ali da ne komplikujem sad. Važno je shvatiti da DB.SubmitChanges() vrši sav hard-work: Insert, Update, Delete. Prije poziva ove procedure, možeš dobiti informacije o tome što čeka na dodavanje, izmjenu, brisanje upotrebom svojstva: DB.GetChangeSet (Inserts, Updates, Deletes).
Kod dobijanja podataka iz baze - najprostije (recimo da treba rezultat prikazati u grid-u pod imenom DataGridView1):
Code:
Me.DataGridView1.AutoGenerateColumns = True
Dim gradovi = From grad in DB.Grads Select grad
Me.DataGridView1.DataSource = gradovi
Preporučujem, ipak, vezivanje grid kontrole za BindingSource i potom punjenje BindingSource-a podacima iz LINQ upita. Pokušaću da napravim jedan kratak tutorijal koji pokazuje sve ovo, samo sa master/detail grid-ovima i 10 linija kod-a u vr' glave. No sad odoh da spavam ... :-)
[ Shadowed @ 25.04.2008. 10:19 ] @
Zahvaljujem, to je tacno ono sto mi je trebalo :)
Jos se predomisljam da li cu koristiti linq, ne znam da li hosting to ima, a ako koristim neki drugi... Ne znam kakvo ce misljenje boss imati o tome :)
[ Djoks @ 25.04.2008. 10:57 ] @
Uh, sad tek vidim da je Web u pitanju ... U ASP-u imaš još bolji mehanizam za rad sa LINQ-om od Windows formi - LinqDataSource. Predlažem da pogledaš odličnu seriju video tutoriala na: http://www.asp.net/learn/LINQ-videos/
Bojim se da hosting provajderi generalno nisu toliko raspoloženi za update .NET Framework-a (isto kao što je to bio slučaj sa PHP-om i verzijama 4.x). Ako si "zapeo" na .NET 2.0 - možeš isto tako relativno brzo doći do rezultata kroz DataSet i TableAdapter. Jedino što nećeš moći da izbjegneš SQL upite upotrebom LINQ-a. Ako ti treba primjer za ovo - javi.
[ deerbeer @ 25.04.2008. 11:02 ] @
LINQ primeri :
http://msdn2.microsoft.com/en-us/library/bb425822.aspx
http://msdn2.microsoft.com/en-us/library/bb308959.aspx
Ne stizem da pregledam sve ..jer ima mnogo da se skroluje :)
Svodi se uglavnom da imas mali sql-engine syntax u tvom c#3.5 kodu koji barata svim podacima na "lokalnom nivou") ;
da ilustrujem ovaj primer :
Code:
using System;
using System.Linq;
using System.Collections.Generic;
class app {
static void Main() {
string[] names = { "Burke", "Connor", "Frank",
"Everett", "Albert", "George",
"Harris", "David" };
IEnumerable<string> query = from s in names
where s.Length == 5
orderby s
select s.ToUpper();
foreach (string item in query)
Console.WriteLine(item);
}
//BURKE
//DAVID
//FRANK
Sto znaci da podaci ne moraju uvek biti na sql-u (xml ,user defined class...bilo sta .)
npr. IQueryable<T> , IEnumerable<T>
Svidja mi se kombinovanje template kolekcija i functor klasa za logicke uslove
Code:
Func<string, bool> filter = s => s.Length == 5;
Func<string, string> extract = s => s;
Func<string, string> project = s => s.ToUpper();
IEnumerable<string> query = names.Where(filter)
.OrderBy(extract)
.Select(project);
jer veoma olaksava kodiranje i izgled koda a samim tim i odrzavanje kad se logicki uslovi menjaju u upitima
Sto se tice LINQ-to SQL sintaksa ustvari ostaje "skoro ista" kao i kad kucas na mssql-u (samo je select prebacen ispod)
Posle toga kako @djoks rece DB.SubmitChanges() koji radi ostali deo posla kao sto su konekcije(open i close)
insert ,update,delete commande od getchanges() itd ..) a taj deo tebi najvise treba kolko sam skapirao ..
[/code]
[ Shadowed @ 25.04.2008. 11:42 ] @
Djoks, na 2.0 nisam zapeo ;)
Linq mi je trebao samo zbog brzeg stancanja klasa, jer je to u pocetnom delu cista daktilografija :)
Hm, na kraju moze da ispadne ova tema fin skup resursa/primera za linq.
[ deerbeer @ 25.04.2008. 12:04 ] @
Ako ti je stvarno deadline onda nemoj raditi u linq-u pogotovu ako ne znas da li ce to svideti boss-u i da li ima na hostingu:)
Idi na sigurnu varijantu
Davno sam pisao dbaccess klase u c# za jedan projekat koje su generisale
update insert i delete komande (za SQLProvider i OleDBProvider) kao i pozivanje stored proc a sql-u
Medjutim to je bilo radjeno odavno u .NET 1.1 i radilo je .NET 2.0 frameworku ..
Ako hoces mogu da ti bacim na mejl (ne bih da kacim ovde da ne bih deplasirao ovako lepu temu )
pa da pogledas da izvuces nesto ako nadjes sto ce da ti skrati put.
Cini mi se koliko se secam da joj treba jos dorade (nije bas bug-free)
[ Djoks @ 25.04.2008. 12:14 ] @
Pogrešno sam se izrazio kada sam pisao "zapeo" - mislio sam: ako si vezan za .NET 2.0 i nemaš drugog izbora.
Ne znam zašto bi pisao sopstvene klase za baratanje podacima i ULUDO potrošio silno vrijeme na implementaciju raznoraznih interfejsa koje DataSet/DataTable već sasvim lijepo imaju? Radije iskoristi GUI za kreiranje DataSet-a i formiranje odgovarajućih DataTable Select/Update/Insert/Delete komandi (bilo da su to SP ili SQL upiti) - i dobićeš hijerarhijsku strukturu koju potom možeš obogaćivati kako god želiš (kroz dodatne upite, kroz expression kolone, dodavanjem sopstvenih metoda i svojstava kroz parcijalne klase itd.). Ne znam zašto tjerate čovjeka da izmišlja toplu vodu, kad sve već ima na gotovo, a rok je tanak!?
[ deerbeer @ 25.04.2008. 12:25 ] @
Odgovor bi bio dajem ono sto imam ...
Tada kad sam koristio tu klasu bio je .NET1.1 i koristio sam TypedDataSet kao podatke i kod koji bi skratio upotrebu ADO.NET- koda u programu(SQLConnection,SQLCommand,SQLParameter itd ..)
al mi se nije svidela upotreba "SQlCommandBuilder"-a jer me je zezao u nekim trenucima pa sam odlucio da sam napisem ..
[ deerbeer @ 25.04.2008. 17:06 ] @
Citat: @deerbeer
Sto znaci da podaci ne moraju uvek biti na sql-u (xml ,user defined class...bilo sta .)
npr. IQueryable<T> , IEnumerable<T>
Svidja mi se kombinovanje template kolekcija i functor klasa za logicke uslove
A evo zasto .... kolko sam uspeo dosad da proucim iz primera:
Kod mozda nije 100% tacan nemam sad kompajler pri ruci :(
Svaka ispravka i komentar je dobrodosao ..
Code:
// npr imam kolekciju contact-a u xml fajlu
<Contacts>
<Contact>
<name></name>
<address></address>
<phone></phone>
</Contact>
....
...
</Contacts>
XElement contacts = XElement.Load(@"c:\myContactList.xml");
IEnumerable<string> query = from c in contacts.Elements("contact")
where (string) c.Element("address").Element("state") == "WA"
orderby (string) c.Element("name")
select (string) c.Element("name");
foreach (c in query) {
Console.WriteLine(c);
}
IEnumerable<XElement> query = from c in contacts.Elements("contact"),
ph in c.Elements("phone")
where (string) c.Element("address").Element("state") == "WA" &&
p h.Value.StartsWith("206")
orderby (string) c.Element("name")
select c;
//vracamo recordset od xml-a
foreach (x in query){
Console.WriteLine(x);
}
Deluje mi skroz super da ne moram da radim query xml-a preko XPath-a
Podsetite se njegove ruzne sintakse ..pogotovu ako ulaze u obzir i neki logicki uslovi
A ovo je mozda glavni benefit od LINQ-a kako kaze MS :
Citat:
The benefit for data source implementers of reusing this deferring functionality by implementing the IQueryable<T> interface is obvious.
To the clients who write the queries, on the other hand, it is a great advantage to have a common type for remote information sources.
Not only does it allow them to write polymorphic queries that can be used against different sources of data,
but it also opens up the possibility for writing queries that go across domains.
Code:
namespace System.Linq {
using System;
using System.Collections.Generic;
public static class Enumerable {
public static IEnumerable<T> Where<T>(
this IEnumerable<T> source,
Func<T, bool> predicate){
foreach (T item in source)
if (predicate(item))
yield return item;
}
}
}
//Ovde je Func<T,bool> kao logicki operator sa bilo kojim tipom ...
string []names = {"Pera","Mika","Laza","Mirko","Slavko" };
Func<string,bool> manjeOd6 = s => s.Length < 6 ;
IEnumerable<string> query = Enumerable.Where(names,manjeOd6);
int [] nizinta = {32,2,34,3,54} ;
Func<int,bool> veceod10 = s => s > 10 ;
IEnumerable<int> query = Enumerable.Where(nizinta,veceod10);
//Ako to sve upakujemo kao funkciju da izgleda kao "SELECT" upit to bi izgledalo
public static IEnumerable <T> Select (IEnumerable<T> source,Func<T,bool> where1,Fucn<T,bool> where2 ..itd...)
//ili mozda jos lepse kao niz Funktora
//ne znam da li ovo dozvoljava c# 3.5 kompajler .
public static IEnumerable <T> Select (IEnumerable<T> source,params Func<T,bool>[] wheres_array) ;
//ako imamo kolekciju objekata
// najbolje je naslediti IQuerable<T> sa kojom dolazi jos mnostvo opcija za expression izraze,agregacije,sorting-om itd .....
public MyQueryEngine<T> : public IQuerable<T>
[ mmix @ 25.04.2008. 18:08 ] @
Re vezanost za 2.0
Posto je .NET 3.5 u osnovi .NET2.0 sa novim klasama, a asp.NET i dalje radi pod 2.0 enginom, teorijski bi mogao da ukljucis "Copy Local" nad svim .NET3.5 referencama i da te .NET3.5 asemblije koji sadrze LINQ ubacis u bin folder i tako dobijes .NET3.5 web aplikaciju pod .net2.0 hostingom  Ne vidim ni jedan razlog zasto to ne bi radilo
Probacu kasnije kad dodjem kuci
[ Shadowed @ 25.04.2008. 22:21 ] @
Haha, ne moz' da omane da pomenes da je 3.5 zapravo 2.0+ ;)
Naravno, ne smeta, s' obzirom da si u pravu.
Uradicu sa linq-om, znam za hosting koji podrzava, nisam ga koristio ali pretpostavljam da je dobar, ili bar dovoljno dobar s' obzirom da sam naisao na njih preko preporuke na MS-ovom sajtu (ne mogu se setiti tacno kako se zove). Zavrsicu stvar u .net-u i dati im, pa neka vide hoce li to ili da nastavimo peripetije sa php-om i cms-ovima :)
A i bar cu imati jednu .net referencu vise, posto me udavise php-om :)
[ 01011011 @ 29.04.2008. 18:04 ] @
Samo da ti javim da LINQ nije standard, ukoliko radis neku aplikaciju, to je nesto sto mikrosoft pokusava da poturi developerima kako bi se na kraju sklonio SQL, sto se nece dogoditi tako imas to u obziru.
[ Shadowed @ 03.05.2008. 10:28 ] @
Ako jedan objekat ima adresu (znaci, klasicno, ulica, grad, drzava...), drzave su u posebnoj tabeli, interesuje me i za kreiranje novog obekta i update postojeceg, kako da ga najbolje da izvedem da koristi postojeci red a ne kreira novi? Da li je dovoljno da objekat.Country.ID postavim na neku vrednost koja postoji u bazi pa ce on biti dovoljno pametan da iskoristi to postojece?
Takodje, grad se isto cuva u zasebnoj tabeli, ali da ne bih unosio sve gradove sveta na pocetku, ostavljam textbox u koji se upisuje (umesto dropdown-a kod drzave). Ono sto mi je potrebno je da kada se upise postojece ime koristi postojeci unos u bazi, kada se upise nesto sto ne postoji, prvo se doda grad.
Sad, znao bih ja to da izvedem na ovaj ili onaj nacin, al' me zanima kako se to standardno radi :)
[ Djoks @ 03.05.2008. 10:51 ] @
Što se tiče izmjene i brisanja podataka iz LINQ-a (bilo kroz uskladištene procedure ili bez njih) - evo par primjera: http://msdn.microsoft.com/en-us/library/bb386927.aspx
Za grad i textbox: mislim da će ti odgovor na ovo pitanje takođe dati link odozgo. Ako ne - napisaću ti jedan primjer.
[ Mikelly @ 03.05.2008. 14:10 ] @
Malo i ja da se ukljucim u raspravu...
Svidja mi se ovi LINQ. Koristeci LINQ to OBJECTS skratio sam huffman kod koji sam u c++ realizovao sa dvostruko povezanim listama sa ne znam ni ja koliko linija koda i pomocnih funkcija na nevjerovatnih desetak linija koda. Ekstra. Sve one MIN, COUNT, SELECT funkcije nad kolekcijama su super.
E sad me interesuje LINQ to SQL, bar dok ne dodje ADO.NET Entity Framework i LINQ to ENTITIES. Najvise me interesuje kako da radim DATA BINDING. Jer, sve one klase koje generise O/R Designer izlazu samo dva dogadjaja: property changing i property changed (i cini mi se da u property changing dogadjaju ne mogu da vidim koji se property mijenja). Sto ja treba da radim, da punim sve sto procitam u neki BindingSource? A kako da izvedem parent-child prikaze? Mogu vala napunit novi BindingSource child zapisima, ali kako da povezem dva BindingSource-a?
LINQ to SQL je ok, zapisi su objekti, prirodnije je i lakse radit s njima, mada su i tipizirani dataset-ovi standardnog ado.net-a imali neke takve karakteristike, ali mu fali sva sila stvari sto su imali datarow i datatable objekti. Ne znam, na prvi pogled mi se cini da je istu stvar mnogo lakse izvesti u ado.net-u nego koriscenjem LINQ to SQL-a (mada vjerovatno, ili prije sigurno to mu nije ni namjena, vec samo da eliminise SQL upite iz aplikacije).
To su moji utisci, ne znam, mozda i grijesim...
Pozdrav.
[ Shadowed @ 03.05.2008. 16:43 ] @
Mikelly, generisane klase mozes prosiriti kako god zelis preko parcijalnih klasa.
Djoks, dobra je strana, ali mi ne pomaze kod ove konkretne stvari. Isprobavacu pa cu videti kako se ponasa :)
[ mmix @ 03.05.2008. 16:47 ] @
Nema tu neke mudrosti, ako je objekat vezan na Country tabelu, imaces efektivno dva polja (pod uslovom da si ih deklarisao u objektu ili si klasu objekta definisao kroz dbml fajl), i onda objekat mozes da vezes na Country na dva nacina,
objekat.CountryId = <postojeci id zemlje> pod uslovom da je COuntryId kljuc
ili
objekat.Country = instanca Country objekta koji si ili kreirao nov ili ucitao iz context-a
Citat: Mikelly: E sad me interesuje LINQ to SQL, bar dok ne dodje ADO.NET Entity Framework i LINQ to ENTITIES. Najvise me interesuje kako da radim DATA BINDING. Jer, sve one klase koje generise O/R Designer izlazu samo dva dogadjaja: property changing i property changed (i cini mi se da u property changing dogadjaju ne mogu da vidim koji se property mijenja). Sto ja treba da radim, da punim sve sto procitam u neki BindingSource? A kako da izvedem parent-child prikaze? Mogu vala napunit novi BindingSource child zapisima, ali kako da povezem dva BindingSource-a?
Ne moras da vezujes dva binding source-a, oni podrzavaju hijerarhijske liste sto LINQ entiteti jesu. Npr u njegovom primeru, Country tabela je vezana za City tabelu, kad izvrsis:
var countries = from c in db.Country select c;
bindingSource.DataSource = countries;
izvrsio si bindovanje i svaki element iz countries ima property Cities koji je IQueryable interfejs koji ucitava gradove koji su vezani za tu zemlju. Naravno svako referenciranje Cities propertija ce izazvati po jedan SQL select u bazu pa je u ovim slucajevima mozda pametnije pre-loadovati sve child entitete cime ce se smanjiti broj SQL skripti koje se izvrse
Code:
DataLoadOptions lo = new DataLoadOptions();
lo.LoadWith<Country>(c => c.Cities);
db.LoadOptions = lo;
var countries = from c in db.Country select c;
bindingSource.DataSource = countries;
Ako bindovani element podrzava hijearhijske liste imaces multi-level prikaz. Fora je jedino sto je binding malo otezan iz samog dizajnera posto je binding dialog u visual studiu malo glup pa ne vidi nista dublje od prvog nivoa, a ni same fabricke kontrole nisu nista mudrije ukljucujuci tu i grid kontrolu. Ja npr koristim Infragistics grid koji to podrzava i dobijam rezulate lepo hijerarhijski:
[att_img]
jedino sto za sada fali je cross-table mapping sto ce valjda da resi taj Entity Framework, al otom potom. Ako bas hoces mozes vec sad da iskoristi LINQ for objects preko LLBLGen generisanih entiteta.
Citat: Mikelly: LINQ to SQL je ok, zapisi su objekti, prirodnije je i lakse radit s njima, mada su i tipizirani dataset-ovi standardnog ado.net-a imali neke takve karakteristike, ali mu fali sva sila stvari sto su imali datarow i datatable objekti. Ne znam, na prvi pogled mi se cini da je istu stvar mnogo lakse izvesti u ado.net-u nego koriscenjem LINQ to SQL-a (mada vjerovatno, ili prije sigurno to mu nije ni namjena, vec samo da eliminise SQL upite iz aplikacije).
LINQ for SQL zapravo olaksava DataSet operacije jer ne moras da generises table adaptere za svaku mogucu primenu koja ti treba, pride nisi mogao da ucitas samo podset polja, datatable ce uvek imati ona polja koja su definisana u tipiziranom datasetu cak iako ih ne ucitas kroz Query (ako uopste i uspes u tome, npr ne mozes preskociti polje iz tabele koje je NON NULL i nema default vrednost). Zamisli da je LINQ runtime dataset generator koji odmah generise tipiziranu tabelu i query koji je popunjava.
[ mmix @ 03.05.2008. 17:12 ] @
BTW, ne znam dal ste primetili ali dbml dizajner kada generise entitete iz baze sam provaljuje plural imena entieta po engleskoj terminologiji, tako ad kad koristis tabela sa nazivima na naskom, npr Radnik, dobijas sledece
var radnici = from r in db.Radniks select r;
[ Shadowed @ 03.05.2008. 18:08 ] @
Jeste. Meni su tabele u mnozini ali je objekte kreirao u jednini (a kolekcije opet u mnozini). Mnogo je bre pametan :)
Isprobao sam ono..
kada uradim ovo on kreira novi hotel i lepo iskoristi postojecu drzavu:
Citat:
Dim h As New Hotel
h.HotelName = "testhotel"
h.Country = (From c In db.Countries Where c.ID = 152 Select c).First()
db.Hotels.InsertOnSubmit(h)
db.SubmitChanges()
Ali kada uradim ovo:
Citat:
Dim h As New Hotel
h.HotelName = "testhotel"
h.Country = New Country() With {.CountryName = "Serbia", .ID = 152}
db.Hotels.InsertOnSubmit(h)
db.SubmitChanges()
Pokusa da napravi novi Country i prijavi gresku jer je ID Identity. E sad, kako on zna da je u jednom slucaju drzava dobijena iz baze a u jednom kreirana "rucno" - pojma nemam :)
[Ovu poruku je menjao Shadowed dana 04.05.2008. u 00:11 GMT+1]
[ mmix @ 03.05.2008. 19:22 ] @
To je zato sto ti je razmisljanje jos uvek fokusirano na DataSet funkcionalnost. Fundamentalna razlika u LINQu je sto entiteti ne cuvaju svoje database stanje, kao sto je to radio DataRow i DataTable, nemas rowstate, nemas dirty flag, nista od toga ne postoji u entitetima, zato su tako i "mrsavi" (sto je sa druge strane dobro kad treba da ih serijalizujes). Sam DataContext objekat cuva reference svih entiteta koje dobije bilo od tebe bilo od baze zajedno sa sync stateom tog entiteta. Kad si ga ucitao u prvoj varijanti, context ga je zapamtio i tako znao da taj podatak vec postoji u bazi, kad si ga kreirao sa New i dodao u kontekst kontekst ga je prihvatio kao novo kreirani entitet i zakljucio da treba da ga posalje bazi kao INSERT.
Isto tako iz tog razloga entiteti implementiray propertychange, tako context uhvati informaciju da si promenio neko polje u objektu i odmah ga markira za update.
Inace, kad radis:
h.Country = (From c In db.Countries Where c.ID = 152 Select c).First()
forsiras select nad Country tabelom u bazi da bi kreirao Country objekat, a vec imas njegov ID, umesto toga uradi samo
h.CountryId = 152;
[ Shadowed @ 03.05.2008. 23:23 ] @
Hah. Ako kreiram nov hotel i hocu da ga submit-ujem, netje da radi :)
Elem, ID mu je Integer i po default-u 0 i vec postoji u tabeli. Mogao bih da uzmem najveci ID iz tabele i dodelim za 1 vise, ali to nije bas lepo resenje a i stavio sam da je ID Identity kolona. Ako probam MyHotel.ID = Nothing, ne prolazi jer nije Nullable i Nothing biva konvertovano u 0 (u C#-u bi mozda izbacio exception).
[ mmix @ 04.05.2008. 09:15 ] @
Nesto ti nije dobro ili u object modelu ili u bazi.
Proveri da li ti je polje u bazi int identity. To je neophodno da bi kljuc bio generisan na nivou baze (gde i treba).
Dalje pogledaj HotelID polje u Hotel entitetu (ne znam da li si koristio dbml ili si sam pravio entitete) u svakom slucaju HotelId property u Hotel entitetu mora da bude okicen sa sledecim parametrima COlumn atributa:
Code:
[System.Data.Linq.Mapping.Column(
AutoSync=AutoSync.OnInsert,
DbType="Int NOT NULL IDENTITY",
IsPrimaryKey=true,
IsDbGenerated=true)]
u suprotnom nece raditi jer ce LINQ for SQL smatrati da polje nije autogenerisano u bazi i probace da insertuje sa konkretnom vrednoscu koja je u propertiju. I btw, odmah da ti kazem da je losa praksa imati identity (0, 1) polje u bazi, bolje pocni od 1 cisto zbog situacija u kojima bi ti 0 predstavljalo zamenu za NULL.
[ Shadowed @ 04.05.2008. 10:50 ] @
Moja greska :\
Nekako (pretpostavljam da sam zaboravio), u bazi nije bilo podeseno da kolona bude identity. Koristim dbml. Promenio sam u bazi, ali nisam znao kako da ga nateram da skonta sam (osim da izbacim pa ubacim tabelu) pa sam samo promenio u property-u za tu kolonu. Atributi su kao sto si naveo.
Ne pravim identity(0,1), ostavljam po default-u (1,1) nego nije bio identity a insertovao sam jedan koji je prosao sa Nothing->0 :)
[ Shadowed @ 28.05.2008. 23:45 ] @
Postoji li neki bolji nacin da se ovo uradi?
Code:
If db.persons.count(function(p as person) p.name="pera") > 0 then
dim pera as person = db.persons.first(function(p as person) p.name="pera").surname="peric"
else
db.insertonsubmit(new person() with {name="pera", surname="peric"})
end if
db.submitchanges()
Znaci, poenta je da ako objekat sa zadatim uslovom postoji bude update-ovan, ako ne postoji kreira se nov. Ovako ima 2-3 upita, moze li bolje? :)
Edit: izvinjavam se na nekoriscenju velikih slova, al' nisam pisao u VS-u...
[ mmix @ 29.05.2008. 11:17 ] @
FirstOrDefault() jeste resenje, ali Take(1) i SqlMethods.Like su visak ovde.
Take(1) ce u ovom kontekstu uraditi TOP(1) sto je isto sto ce uraditi i FirstOrDefault() samo sto ce upotreba ova dva metoda uporedo izazvati kreiranje subquery-a u SQL-u ( select TOP 1 t1.lista from (select top 1 t0.lista from t0 where LIKE operator) as t1) sto je suboptimalno.
SqlMethods.Like generise LIKE operator bez implicitnog % (koje generise BeginsWith i EndsWith) i kao takav ovde nije bas primenljiv posto on ima eksplicitnu jednakost. Dakle, najefikasnije resenje koje moze da ponudi LINQ to SQL je sa dve skripte:
Code:
Dim p = (From o In DB.Persons Where o.FirstName = "Pera" Select o).FirstOrDefault()
If p Is Nothing Then
DB.Persons.InsertOnSubmit(New Person With {.FirstName = "Pera", .LastName = "Peric"})
Else
p.LastName = "Peric"
End If
DB.SubmitChanges()
[ Shadowed @ 29.05.2008. 11:24 ] @
To sam i ja prvo mislio, ali u MSDN-u kaze:
Citat: Return Value
Type: TSource
default(TSource) if source is empty; otherwise, the first element in source.
pa nisam bio siguran da li ce biti Nothing ako nema rezultata u bazi. Mada, meni bi bilo logicno da i .First vraca Nothing ako nema rezultata (ovo bi mi do sada olaksalo gomilu stvari :)).
[ mmix @ 29.05.2008. 13:19 ] @
Citat: Shadowed: pa nisam bio siguran da li ce biti Nothing ako nema rezultata u bazi. Mada, meni bi bilo logicno da i .First vraca Nothing ako nema rezultata (ovo bi mi do sada olaksalo gomilu stvari  ). default ima smisla samo kad query transformise objekat u value type, npr akd vracas ID koji je int, FirstOrDefault() ce vratiti nula ako nema redova, za sve reference tipove default vrednost je null (nothing)
Citat: Djoks: - Što se tiče SqlMethods - može se izbaciti, ali sam je uveo namjerno zbog primjera njene upotrebe (što sam i napisao). Može biti pogodna zbog svojih funkcija za baratanje datumima... Tvoj kod bih, mmx, ipak izmijenio i zadržao ili LIKE ili SqlMethods iz prostog školskog razloga: imena u SQL upitima valja porediti sa LIKE. Mnogo elegantnije nego uvođenje ToUpper, ToLower itd. U protivnom: "Najdanović" != "NAJDANOVIĆ" != "najdanović" što kod imena/prezimena/naziva ne smije biti slučaj.
- Na kakve dvije skripte misliš?
SqlMethods postoji samo iz jednog razloga, da linq to sql query-je snabde operacijama koje nisu mogle da se uglave u "standardne" metode tipova kojima se barata, sto ovde ukljucuje transformacije datuma i LIKE bez implicitnih wildcards (imaj samo u vidu da LIKE bez wildcards radi isto sto i "=" operator) da bi mogao da pravis LIKE operacije koristeci custom patterns, sto ne mozes kroz metode i ekstenzije string tipa (izuzev ogranicenih 'pattern%' i '%pattern' pretrazivanja kroz navedene BeginsWith i EndsWith metode, npr za pattern nalik 'pera ___ic', tj sve pere koje se prezivaju na pet slova sa ic moras da koristis SqlMethods.Like)
Tvoja primedba sa skolskom primenom LIKE takodje nema osnova. .NET CLR jeste case sensitive ali LINQ to SQL nasledjuje case i collation iz baze sa kojom operise, tako da ako ti je sama baza case insensitive Pera i PERA su isto, a sve i da ti je baza case sensitive LIKE ti nece preskociti to i zaboraviti da poredi case stringova. Pride je LIKE skuplji jer mora da skenira ceo index/kolonu, a posebno to sto LIKE trtira %, ^, [, ], _ kao wildcards pa je za unete parametre koji ih sadrze kao literale neophodno preformatirati string pre slanja u LIKE. Prvi put cujem da neko propoveda upotrebu LIKE bez wildcards kao efiksaniju zamenu za =, to jednostavno ne pije vodu.
Dve skripte:
Code: Dim p = (From o In DB.Persons Where o.FirstName = "Pera" Select o).FirstOrDefault() generise prvu SQL skriptu
a DB.SubmitChanges() generise drugu, bilo insert bilo update, u zavisnosti od toga kojom granom je IF prosao.
Copyright (C) 2001-2025 by www.elitesecurity.org. All rights reserved.
|