Software


Recent am avut o problema cu un client care avea o baza de date foarte mare iar functionalitatea care aducea o lista de elemente dura mai mult de 5-10 secunde. In mod normal, se pune un mesaj de “stati pe loc, ca lucrez”, “loading” ceva…

Partea proasta la IE este ca de exemplu pui un DIV frumos si colorar sa se afiseze, va sta ca boul sa se termine requestul Ajax, moment in care nu ma mai intereseaza, pentru ca eu deja vreau sa il ascund.

O solutie temporara, in lipsa de altceva mai bun, este sa pornesti requestul intr-o functie setTimeout() ca sa dai timp la IE sa isi afiseze DIVul, mesajul, etc si peste 500 de milisecunde sa dai drumul la request. Ceva de genul:

waitPlease(‘Loading stuff…’);

setTimeout(“executeStuffSearch()”, 500);

Evident, ca daca in divul respectiv e o imagine cu gif animat (o rotita de exemplu) aia va sta inghetata tot timpul cit IE asteapta sa-i vina raspunsul la request. Btw, mentionez ca requestul este sincron…

Alte idei?

Se da o aplicatie careia vrei sa-i testezi compatibilitatea cu W2008R2. Trebuie sa o instalezi pe versiunea x64Enterprise intr-o masina virtuala Hyper-V altfel testul esueaza.
Am aflat asta “the hard way” dupa ce am facut 2 masini virtuale cu vmware, ca evident ca nu am citit manualul :)
Asa ca mai stau in pic…

Se dă o aplicaţie la care trebuie sa faci un kit de instalare. Toate bune şi frumoase până când trebuie să automatizezi setările din web.config, că doar nu o să-l rogi frumos pe webadmin să facă configurările de mână.

Drept urmare, trebuie să faci un CustomInstaller care deschide web.configu, scrie ce e de scris si apoi inchide (nu înainte de a salva).

Ca să se persiste modificările tale trebuie sa ştergi respectiva configurare din instanţa pe care o manipulezi şi să oadaugi din nou cu setările dorite. Astfel, daca ai ceva prin appSettings, se face în felul următor:

AppSettingsSection appsettings;
appsettings = (AppSettingsSection)config.GetSection(“appSettings”);
appsettings.Settings.Clear();
appsettings.Settings.Add(“MailFrom”, mailAddress);
appsettings.Settings.Add(“MailUser”, mailFrom);

… şi aşa mai departe

Sau dacă ai un ApplicationSettingsGroup mai ciudat, ar fi bine să ştergi fiecare SettingElement şi apoi să-l adaugi corespunzător.

de exemplu:

appsettings = (ApplicationSettingsGroup)config.GetSectionGroup(“applicationSettings”);
ClientSettingsSection css = (ClientSettingsSection)appsettings.Sections[0];
ConfigurationElement[] sett = new ConfigurationElement[css.Settings.Count];
css.Settings.CopyTo(sett, 0);
css.Settings.Clear();
foreach (SettingElement se in sett)
{
string wsLocation = se.Value.ValueXml.InnerText;
wsLocation = wsLocation.Replace(“localhost”, webServicesurl);
XmlNode node = se.Value.ValueXml.ChildNodes[0];
node.Value = wsLocation;
css.Settings.Add(se);
}

… că altfel înnebuneşti două ore căutând permisiuni pe fişiere, etc.

Nu sunt rare cazurile în care avem nevoie de un LEFT JOIN prin selecturile de la casa omului şi deoarece LINQ nu are operator LEFT JOIN dedicat, trebuie rezovată problema într-un fel…

Deci, dacă ai nevoie de un SELECT de genul:

SELECT

t0.ID_REC_PROJECT_TARGET AS _targetId, t0.ID_PERSON AS _personId, t0.ID_PROJECT AS _projectId, t5.COMPANY_NAME AS _company,

t4.POSITION AS _position, t2.VALUE AS _priority, t3.VALUE AS _source, t0.COMMENT AS _comments

FROM

dbo.REC_PROJECT_TARGET AS t0

INNER JOIN dbo.PERSON AS t1 ON t0.ID_PERSON = t1.ID_PERSON

INNER JOIN dbo.REC_LOOKUP AS t2 ON t0.ID_PRIORITY = t2.ID_REC_LOOKUP

INNER JOIN dbo.REC_LOOKUP AS t3 ON t0.ID_SOURCE = t3.ID_REC_LOOKUP

LEFT OUTER JOIN dbo.PERSON_WORKEXPERIENCE AS t4 ON (t4.IS_PRESENT = 1) AND (t1.ID_PERSON = t4.ID_PERSON)

LEFT OUTER JOIN dbo.COMPANY AS t5 ON t4.ID_COMPANY = (t5.ID_COMPANY)

El se traduce în LINQ în felul următor:

from t in dac.REC_PROJECT_TARGETs

join p in dac.PERSONs on t.ID_PERSON equals p.ID_PERSON

join lp in dac.REC_LOOKUPs on t.ID_PRIORITY equals lp.ID_REC_LOOKUP

join ls in dac.REC_LOOKUPs on t.ID_SOURCE equals ls.ID_REC_LOOKUP

join wp in dac.PERSON_WORKEXPERIENCEs on p.ID_PERSON equals wp.ID_PERSON into wpl

from wpo in wpl.Where(wpo => wpo.IS_PRESENT).DefaultIfEmpty()

join co in dac.COMPANies on wpo.ID_COMPANY equals co.ID_COMPANY into cpu

from c in cpu.DefaultIfEmpty()

where t.ID_PROJECT == projectId

select new {t.ID_REC_PROJECT_TARGET,

t.ID_PERSON,

t.ID_PROJECT,

c.COMPANY_NAME,

wpo.POSITION,

lp.VALUE,

ls.VALUE,

t.COMMENT}

Partea interesantă (cea cu LEFT JOIN in LINQ) este următoarea:

LEFT OUTER JOIN dbo.PERSON_WORKEXPERIENCE AS t4 ON (t4.IS_PRESENT = 1) AND (t1.ID_PERSON = t4.ID_PERSON)

se traduce:

join wp in dac.PERSON_WORKEXPERIENCEs on p.ID_PERSON equals wp.ID_PERSON into wpl from wpo in wpl.Where(wpo => wpo.IS_PRESENT).DefaultIfEmpty()

Acuma, dacă vrem să complicăm lucrurile puţin, am nevoie sa imi aduc doar acele date care nu au referinte prin alte tabele, adică:

SELECT

t0.ID_REC_PROJECT_TARGET AS _targetId, t0.ID_PERSON AS _personId, t0.ID_PROJECT AS _projectId, t5.COMPANY_NAME AS _company,

t4.POSITION AS _position, t2.VALUE AS _priority, t3.VALUE AS _source, t0.COMMENT AS _comments

FROM dbo.REC_PROJECT_TARGET AS t0

INNER JOIN dbo.PERSON AS t1 ON t0.ID_PERSON = t1.ID_PERSON

INNER JOIN dbo.REC_LOOKUP AS t2 ON t0.ID_PRIORITY = t2.ID_REC_LOOKUP

INNER JOIN dbo.REC_LOOKUP AS t3 ON t0.ID_SOURCE = t3.ID_REC_LOOKUP

LEFT OUTER JOIN dbo.PERSON_WORKEXPERIENCE AS t4 ON (t4.IS_PRESENT = 1) AND (t1.ID_PERSON = t4.ID_PERSON)

LEFT OUTER JOIN dbo.COMPANY AS t5 ON t4.ID_COMPANY = (t5.ID_COMPANY)

LEFT OUTER JOIN dbo.REC_EVENT AS t6 ON (t0.ID_PROJECT = t6.ID_PROJECT) AND (t0.ID_PERSON = t6.ID_PERSON)

LEFT OUTER JOIN dbo.REC_PROJECT_TARGET_REJECTED AS t7 ON t0.ID_REC_PROJECT_TARGET = t7.ID_REC_PROJECT_TARGET

WHERE (t0.ID_PROJECT = @p0) AND (t6.ID_REC_EVENT IS NULL) AND (t7.ID_REC_PROJECT_TARGET_REJECTED IS NULL)

Practic, vreau să elimin din recordsetul meu, înregistrările care apar prin tabelele REC_EVENT respectiv REC_PROJECT_TARGET_REJECTED.

Astfel, construcţia LINQ arată aşa:

from t in dac.REC_PROJECT_TARGETs

join p in dac.PERSONs on t.ID_PERSON equals p.ID_PERSON

join lp in dac.REC_LOOKUPs on t.ID_PRIORITY equals lp.ID_REC_LOOKUP

join ls in dac.REC_LOOKUPs on t.ID_SOURCE equals ls.ID_REC_LOOKUP

join wp in dac.PERSON_WORKEXPERIENCEs on p.ID_PERSON equals wp.ID_PERSON into wpl

from wpo in wpl.Where(wpo => wpo.IS_PRESENT).DefaultIfEmpty()

join co in dac.COMPANies on wpo.ID_COMPANY equals co.ID_COMPANY into cpu

from c in cpu.DefaultIfEmpty()

join re in dac.REC_EVENTs on new { t.ID_PROJECT, t.ID_PERSON } equals new { re.ID_PROJECT, re.ID_PERSON } into tempEvents from events in tempEvents.DefaultIfEmpty()

join rj in dac.REC_PROJECT_TARGET_REJECTEDs on t.ID_REC_PROJECT_TARGET equals rj.ID_REC_PROJECT_TARGET into tempRej from rejected in tempRej.DefaultIfEmpty()

where t.ID_PROJECT == projectId && object.Equals(null, events.ID_REC_EVENT) && object.Equals(null, rejected.ID_REC_PROJECT_TARGET_REJECTED)

select new {t.ID_REC_PROJECT_TARGET,

t.ID_PERSON,

t.ID_PROJECT,

c.COMPANY_NAME,

wpo.POSITION,

lp.VALUE,

ls.VALUE,

t.COMMENT}

Se observă că au aparut cele două tabele in body-ul selectului, însă au apărut şi două elemente noi în clauza WHERE: object.Equals(null, events.ID_REC_EVENT) && object.Equals(null, rejected.ID_REC_PROJECT_TARGET_REJECTED)

Nu am folosit events.ID_REC_EVENT == null deoarece in SQL ar fi arătat aşa: t6.ID_REC_EVENT = NULL şi sunt sigur că nu era de dorit :)

Am inceput un proiecţel nou şi am zis ca daca tot e micuţ, să il facem cu LINQ, sa fie ca şi proof of concept.

Imi place… 

Cel mai mult mi-a dat batai de cap cum se replică o construcţie de genul

SELECT UnCâmp FROM Cutare WHERE AltCâmp IN 1,2,3,4

si iese chiar interesant:

from u in dataContext.Cutares where listaMea.Contains(u.AltCâmp)
select u.UnCâmp

 

 

Bun, ştim că Target, ZF si Business Magazin sunt fraţi, da chiar împart şi aceeaşi programatori?

O mostră de SQL apărut pe sait azi:

select *,(select financialobject_value from financialobject where financialentity_id = 4 and financialobject_title = A.financialobject_title and financialobject_datetime = (select DISTINCT financialobject_datetime from financialobject order by financialobject_datetime DESC LIMIT 1,1) ) as previousvalue from financialobject as A where financialentity_id = 4 and financialobject_datetime = (select DISTINCT financialobject_datetime from financialobject order by financialobject_datetime DESC LIMIT 0,1)

Tare, nu?

Poza mai jos:

AlteDude

Via Endgadget :)

O nouă versiune de Windows, specială pentru Egipt.

new_windows.preview

Ketchup flavour ?? :)

De azi am instalat un timesheet pentru Team Foundation Server. Este un add-on la Team System Web Access, de pe CodePlex.

Acuma nu mai am cum sa ma fofilez :)

Impresiile sunt plăcute (probabil pentru că sunt colaborator extern și băieții se poarta frumos).

Marți și miercuri am reușit să mă conectez la ERP și să arunc ceva date pe o aplicație web, folosind conectorii specializați (și funcții BAPI).  Cu ocazia asta, am mai căpătat niște cunoștințe: știu acum să extrag date din ERP-ul cu pricina și să vizualizez date într-un mod plăcut ochiului (și clientului).

Aseară am fost în Mannheim pe la cumpărături, unde m-am întilnit și cu Moș Niculae cu ceva cadouri :)

De ieri dimineață este disponibil pentru download versiunea 2008 a editorului meu preferat: Visual Studio.

http://msdn2.microsoft.com/en-us/subscriptions/default.aspx

Nu e pentru toată lumea ci doar pentru cei care au abonament MSDN (fie platit direct, fie prin diverse tipuri de parteneriat)

Să vedem dacă de data asta, rapoartele Crystal o sa ruleze tot de două ori procedurile stocate din spate… :)

Next Page »