LINQ 2 SQL a DataLoadOptions

Už som si myslel, že som objavil nejakú chybu v LINQ 2 SQL, ale zase to bol skôr problém medzi klávesnicou a stoličkou. Mám nasledovný dátový model.

DB model

Zároveň som pri načítavaní kontaktov nastavil, aby sa spolu s nimi načítali aj EmailType a TelephoneType. Proste aby sa nepoužil lazy-loading. Zabezpečil som to nasledovným kódom.

partial void OnCreated()

{

var dlo = new DataLoadOptions();

dlo.LoadWith<EmailContact>(ec => ec.EmailType);

dlo.LoadWith<TelephoneContact>(tc => tc.PhoneType);

LoadOptions = dlo;

}

Táto OnCreated metóda je priamo v triede odvodenej od DataContext.

Lenže som sa veľmi čudoval, keď pri načítaní kontaktov sa mi vrátil prázdny zoznam, aj keď samozrejme nejaké dáta v DB boli. Ešte že debbuger zobrazuje SQL príkaz, ktorý sa posiela na SQL Server. A ten bol nasledovný.

SELECT [t0].[ContactType]

FROM [Customer].[vContact] AS [t0]

INNER JOIN [Customer].[vTelephoneType] AS [t1] ON [t1].[Id] = [t0].[PhoneTypeId]

INNER JOIN [Customer].[vEmailType] AS [t2] ON [t2].[Id] = [t0].[EmailTypeId]

WHERE [t0].[CustomerId] = @p0

A je jasné, že tento príkaz musí zakaždým vrátiť prázdny zoznam. Ak je v riadku uložený EmailContact, tak stĺpec PhoneTypeId je NULL, a teda vďaka operátoru INNER JOIN na view vTelephoneType sa tento riadok do výsledku nedostane. A naopak, ak je v riadku uložený TelephoneContact, tak stĺpec EmailTypeId je NULL, a zase vďaka operátoru INNER JOIN na view vEmailType sa tento riadok do výsledku nedostane. A prípad pre PostAddressContact ani netreba rozpisovať, pretože tam sú obidva stĺpce NULL.

Najprv som si myslel, že programátori z MS spravili škôlkarskú chybu a dávajú INNER JOIN aj tam kde má byť LEFT JOIN. Ale začal som pátrať hlbšie, a tak som si otvoril .NET Reflector. Ešte raz vďaka za tento najdôležitejší nástroj .NET developera. A tam som po dlhšom pátraní zistil, že predsa len sa niekedy používa LEFT JOIN a niekedy INNER JOIN. Ak stĺpec, ktorý obsahuje referenciu na nejakú entitu, nie je nullable a je na ňom definovaný foreign key, tak použije INNER JOIN, inak sa použije LEFT JOIN. Čo je celkom logické, pretože ak sú splnené tie dve podmienky, tak sa nám v SQL databáze nepodarí vložiť do daného stĺpca inú hodnotu, ako sa nachádza v referencovanej tabuľke. Takže INNER JOIN má za daných podmienok zmysel, pretože vždy bude existovať záznam v referencovanej tabuľke. Nezistil som síce ako zisťuje, či je nad daným stĺpcom fereign key, pretože táto možnosť sa nikde v LINQ 2 SQL designery nezadáva.

Ale to nie je dôležite. Dôležite je, že mne stačilo zmeniť vlastnosti EmailTypeId a PhoneTypeId z int na Nullable<int> a všetko funguje tak, ako má. Samozrejme, že v databáze tieto stĺpce boli NULL, ale v Class modely neboli, pretože z business pohlady EmailContact musí mať uvedený EmailType a TelephoneContact musí mať uvedený TelephoneType. Takže, ak nikto nepokazí dáta v databáze, tak v Class modely dané vlastnosti nemuseli byť nullable.

Zaradené do: , ,

Komentáre

# vlko said:

Nullable<int> je tazko citatelne staci pouzit C# variaciu:

int?

A v C# 3.0 je aj uzitocny operator  x ?? y co je v preklade

(x !=null) ? x : y

Thursday, October 09, 2008 8:49 PM
# duracellko said:

diik.. int? pouzivam.. len v clanku som mal pocit, ze to bude vyzerat ako otaznik na konci vety, tak som to radsej napisal univerzalne. A vlastne tym myslim aj na VB citatelov :)

Friday, October 10, 2008 9:07 AM
# vlko said:

Jaj vidis, to ma nenapadlo:)

Aj ked vo vb.net by to malo byt Nullable(of Integer) a okrem toho prave vo vb sa pouziva tiez zapis Integer?.

Este pozeram do overview vb.net (msdn.microsoft.com/.../ms364068.aspx) a veru ani lambdu maju inaksiu

Funkcion( x) x < 5

Takze na ziadnych VB citatelov nemyslis:)

Friday, October 10, 2008 12:59 PM
Prihlásiť | Registrovať | Pomoc