.. är en styggelse som jag inte kommer ifrån på ett snyggt sätt i mitt nuvarande projekt. För att göra en lång histora kort så här är mitt problem. Jag tycker inte att cirkulära referenser är regelmässigt dåliga, det var en befrielse att slippa den COM-begränsningen. Nu vet jag inte med VS2008. Men i tiidage versioner av VS så har jag/vi fått problem med kompileringar när cirkulärar referenser varit inblandade, VS har ofta fått problem med referenserna till de olika dll:erna... Cirkulära referenser mellan assemblies är inte bra nej, iom att du får höna-ägg problem ifall du försöker bygga koden från tomt bord. Kan du inte bara göra en deep-copy på det object som finns i cachen istället för att ersätta det? Eftersom jag säger att 2 objekt som har samma ID är samma objeket, så kommer det betyda att ett objekt i cachen och ett objekt i ett annat objekt är "samma objekt". Problemet blir då när objektet har blivit uppdaterat och läggs i cachen, så kommer inte detta objekt att ändras i alla de andra objeketen som har detta objeket som en referens. Invecklat??? Nu är jag bakfull som satan och kan ha missuppfattat både ett och annat, men på sista posten låter det som att du istället skulle kunna vända på det; låt servern ha referenser utåt och propagera alla ändringar direkt? Ja det skulle kunna vara en lösning, men då måste jag ju ändå hålla koll på vilka objekt som har relationer mellan varandra och komma ihåg att skriva kod så att alla objekt blir uppdaterade när väl ett objekt sparas...Cirkulära referenser...
Jag har en server och flera klienter. För att öka prestanda på klienten, minska belastningen på servern och trafiken över nätverket, så har alla klienter en ganska stor inmemory cache. Typ en lång lista med 'Country' och även en lång lista med 'Currency'. Varje 'Country' har sedan ett 'Currency' objekt i sig. Varje 'Currency' har en lista med 'CurrencyRates'. Alltså en lista med olika valutakurser för olika tidsaspekter. Detta så man skall kunna valutasäkra sig.
Så om jag har objektet USA ('Country') så har den ett USD ('Currency') objekt i sig och detta 'Currency-objekt' har en lista med olika 'CurrencyRates'. Om jag nu vill gå in och ändra på en valutakurs eller lägga till en ny kurs, så går jag in till mitt 'Currency' objekt och ändrar i denna lista. Detta 'Currency-objekt' skickas sedan till serven och sparas.
För att alla andra klienter skall veta att 'Currency-objektet' är sparat så får de reda på detta och får tag i det nya 'Currency-objektet' och uppdatera sina cachar med detta objekt. Så om jag nu går in en annan klient och tittar på USD ('Currency') så ser jag att 'CurrencyRate' har ändrats. Men om jag går in och tittar på USA ('Country') och tittar på dess 'Currency' objekt, så har dessa ändringar inte slagit igenom. Det är helt naturligt då detta objekt inte är samma objekt som det som finns i cachen.
Mitt problem här är alltså hur jag på smidigaste sätt skall få till en uppdatering av mitt 'Currency' i 'Countryt' så det motsvara det objektet som finns i 'Currency'-cachen (som ju är uppdaterat). Jag kan se 2 lösningar. Att vid varje uppdatering av cachen loopa igenom alla mina country-objekt och se om de innehåller ett USD ('Currency-objekt') och uppdatera detta. Problemet här är att det är bra många fler relationer än bara mellan Country-Currency som detta skall göras på, och dessutom så är jag rädd att om jag skapar ett nytt objekt som har en relation till Currency så kommer jag glömma att ändra i koden så även detta objekt blir uppdaterat.
Min andra lösning var att istället för att ha ett fysiskt 'Currency-objekt' i mitt 'Country-objekt' så har jag bara ID:et på currency. Och varje gång som jag vill ha tag i Currency-objektet så får jag anropa mot min cache och leta fram rätt 'Currency-objekt' i cachen och returnera det. Smidigt alltid säker på att få det senaste objektet, och jag behöver inte oroa mig för att glömma ändra i koden, när jag skriver något nytt objekt. Då stötter man genast på problemet att jag använder mig av Binding i WPF, och använder mig då av Country.Currency-properties för att binda data från mitt 'Country-objekt' till controler på sidan. Det betyder att jag så fall får göra anropen till cachen i från min properties i entity. Inte snyggt men överkomligt. Problemet är bara att här kommer jag få en cirkulär referens, eftersom mitt cache har en referens till mina objekt, och mina objekt behöver en referens till min cache... arrgghhghgh...
Tänkt att man kanske kunde lösa det med ett Interface och en Reflektion för att slippa den "hårda" referens. Men då flyttar jag bara problemet till mitt Interface istället. Så den lösning som jag kan se är att jag lägger mitt Cache-interface i mitt Entity-bibliotek. Och så får mitt cache-bibliotek ha en referens till mitt entity-bibliotek. Inte speciellt snyggt, och inge lösning som jag är stolt över, men jag ser ingen annan bra utväg. Någon som har ett annat förslag som är bättre.
Så hur löser ni problem med cirkulära referenser när ni får dem...
- MSv: Cirkulära referenser...
Varför vill du absolut få bort dem?
/johan/Sv:Cirkulära referenser...
Men om det inte är något problem (har inte ens testat) så tänker jag lösa det genom att att använda mig av Interfacet i en egen assembly, så får den ciruklärar referense ligga där...
- MSv: Cirkulära referenser...
Sv: Cirkulära referenser...
public void CurrencyUpdate(Currency newvalue) {
Currency oldvalue;
if (currencycache.TryGetValue(newvalue.name, out oldvalue)) {
oldvalue.rates = newvalue.rates;
oldvalue.,,, = newvalue...
}
else
currencycache.Add(newvalue.name, newvalue);
}
All countryobjekt som refererar till currencyobjektet i cachen blir då uppdaterade.Sv:Cirkulära referenser...
- MSv: Cirkulära referenser...
Sv:Cirkulära referenser...
Jag beslutade mig för att skriva om mina entiteter på klienten så att de inte håller ett objekt, utan får ett id. Och när man sedan skall hämta objektet, så går propertiesen in i min cachemanager och hämtar ut det aktuella objektet. Blev en hel del att skriva om då jag (av lathet) hade samma entiter på klienten som servern, så jag fick helt enkelt skriva om större delen av koden. Har precis fått allt att kompilera och skall testa så det fungerar som jag har tänkt...
La även mitt interface till min CacheManager i mitt Entity-assembly och använder mig av Activator för att skapa ett cachemanager objekt. Så jag slipper cirkulära referenser, men är inte helt nöjd med placeringen av mitt cachemanager-interface, men det får vara så...
- M