Správičky 2 797 Blogy 945 Fórum 18 535

Prehľad diskusie

photo
LINQ to SQL DataContext strategia
mma
21. 9. 2017 22:50:24
photo
RE: LINQ to SQL DataContext strategia
harrison314
22. 9. 2017 9:37:39
photo
RE: LINQ to SQL DataContext strategia
mma
22. 9. 2017 10:00:13
photo
RE: LINQ to SQL DataContext strategia
harrison314
25. 9. 2017 15:41:11
photo
RE: LINQ to SQL DataContext strategia
mma
25. 9. 2017 22:34:54
photo
RE: LINQ to SQL DataContext strategia
macop
26. 9. 2017 12:11:37
photo
RE: LINQ to SQL DataContext strategia
harrison314
26. 9. 2017 13:01:44
photo
RE: LINQ to SQL DataContext strategia
liero
26. 9. 2017 13:32:28
photo
RE: LINQ to SQL DataContext strategia
mma
26. 9. 2017 15:29:05
photo
RE: LINQ to SQL DataContext strategia
liero
27. 9. 2017 17:40:55
photo
RE: LINQ to SQL DataContext strategia
mma
27. 9. 2017 22:46:38
photo
RE: LINQ to SQL DataContext strategia
liero
28. 9. 2017 9:00:58
photo
RE: LINQ to SQL DataContext strategia
liero
29. 9. 2017 12:02:12

LINQ to SQL DataContext strategia

photo
mma
21. 9. 2017 22:50:24
Body: 25
Najaktívnejší č.: 237

LINQ to SQL DataContext strategia

Ahojte,

chcem sa poradit o strategii pouzitia DataContext-u pre LINQ SQL. V poslednej dobe som o tom vela cital na forach a blogoch, ako vytvarat DataContext vzdy na "unit of work". Robim programy do priemyslu, vzdy je to nejaka desktop aplikacia, kde sa najprv z tabulky typov v DB vyberie nejaky typ vyrobku, a potom ako bezi vyroba sa postupne plni tabulka s protokolmi (vysledkami) pre kazdy spracovany vyrobok, prip. data do nejakych podtabuliek. Okrem toho, tieto zapisy prebiehaju v druhom vlakne. Momentalne to mam riesene tak, ze mam jeden globalny DataContext, co ma dve nevyhody, ze jednak sa mozu tie vlakna pobit a program spadne, a druhu, ked program bezi dlhsie bez restartu, spotrebovava pamat, uz som videl jeden bezat 3 mesiace, obsadenych cez 3GB pamate, totalne spomaleny, az hlasil timeouty. Podla toho co som cital toto nie je spravny pristup.

Ako to najlepsie urobit? Napada ma mat jeden DataContext pre ten vybraty typ, z ktoreho nacitam typ, a potom pre kazdy protokol vytvarat novy DataContext, aj spolu s novym spojenim na DB. Pri ukladani protokolov ale potom nesmiem nastavit referenciu na typ, iba nastavit jeho ID, aby sa protokol nepripojil k DataContextu pre typ. Novy protokol sa vytvara zhruba raz za 5-30s. Vytvarat vzdy nove spojenie na DB je asi v poriadku, este  ked sa automaticky pouzije connection pool. Alebo ako to najlepsie vymysliet?

[Reakcia]

photo
harrison314
22. 9. 2017 9:37:39
Body: 1070
Najaktívnejší č.: 24

RE: LINQ to SQL DataContext strategia

Najlepsie je to robit tak ako si povedal -Unit of Work.

Na kazdu samostatnu operaciu s databzou si vytvoris novu isntanciu Db contextu, ktoru aj disposnes.

Akykolvek globalny alebo zdielany db context ti prinesie len problemy.

 

[Reakcia]

photo
mma
22. 9. 2017 10:00:13
Body: 25
Najaktívnejší č.: 237

RE: LINQ to SQL DataContext strategia

Dik. Akurat teda ten typ musim drzat globalne cely cas, lebo z neho a prip. podtabuliek citam kadejake parametre, to asi nema zmysel vzdy nacitavat znovu. A co spojenie? Tiez vzdy vytvarat nove? Ja som zvykol drzat otvorene spojenie, ktore som kontroloval, tym som aj vedel, ze program je pripraveny na novy vyrobok, aby sa nestalo ze zbehne proces a potom zistim, ze nie je spojenie na DB. Ale tak asi je mala pravdepodobnost, ze ked nacitam typ, ze by sa mi nasledne nepodarilo otvorit spojenie, ked to bezi na tom istom pocitaci. Navyse je connection pool, tak pokym to nebude moc dlho necinne, zrejme sa aj tak pouzije predosle otvorene.

[Reakcia]

photo
harrison314
25. 9. 2017 15:41:11
Body: 1070
Najaktívnejší č.: 24

RE: LINQ to SQL DataContext strategia

Nmusis si drzat nic cely cas, doraz si  entity (z EF) mimo kontext je podla mna velka chyba navrhu.

Ked to spravis poriadne (nedrzat si DB context ani entity globalne), tak dopyty do databazy budu rovnake.

A aplikacia ti nebude drzat v RAM niekolko GB.

 

[Reakcia]

photo
mma
25. 9. 2017 22:34:54
Body: 25
Najaktívnejší č.: 237

RE: LINQ to SQL DataContext strategia

No neviem. Funguje to tak, ze po zapnuti obsluha vyberie typ / zada zakazku, nacitaju sa parametre, tolerancie, skompiluje sa sekvencia testu a dalsie, pocas toho sa vyhlasuju chyby, ak nieco nie je. A ak to vsetko prebehne bez chyby, povazuje sa program za pripraveny. Nasledne potom uz automaticky pride novy vyrobok, nejaky cas sa spracovava, pocas testu sa pouzivaju vsetky tie parametre. A ako by som to teda mal urobit, ked nie drzat tie objekty v pamati? Mal by som akoze za "unit of work" povazovat jeden test, pred kazdym vyrobkom to vsetko znovu nacitat a kompilovat? Toto sa mi zda byt spravne, obsluha vyberie parametre, povie s tymto nastavenim chcem teraz niekolko hodin bezat. Navyse ked to uz raz prebehne, predpoklada sa, ze parametre su ok, ze sa nebudu menit a nepredpoklada sa, ze by to uz mohlo hlasit nejake chyby okolo toho. Niekolko GB nebude drzat, to je ten problem, ze som mal cely cas jeden globalny kontext, ked pre ulozenie dalsieho protokolu vytvorim vzdy novy, budem drzat v pamati len tie parametre.

[Reakcia]

photo
macop
26. 9. 2017 12:11:37
Body: 685
Najaktívnejší č.: 32

RE: LINQ to SQL DataContext strategia

Co presne znamena "skompiluje sa sekvencia testu"?

[Reakcia]

photo
harrison314
26. 9. 2017 13:01:44
Body: 1070
Najaktívnejší č.: 24

RE: LINQ to SQL DataContext strategia

Ja som vravel o Globalnom Db contexte

[Reakcia]

photo
liero
26. 9. 2017 13:32:28
Body: 9290
Najaktívnejší č.: 6

RE: LINQ to SQL DataContext strategia

Odporucane strategie sa mozu lisit ak riesis backend a ak riesis nejaku dektopovu aplikaciu, ktora priamo pristupuje k DB.

Co je tvoj pripad?

 

 

[Reakcia]

photo
mma
26. 9. 2017 15:29:05
Body: 25
Najaktívnejší č.: 237

RE: LINQ to SQL DataContext strategia

Skompilovat sekvenciu testu, tak mame tam nieco ako davkovy subor, pri vybere typu sa to parsuje a vytvara sa list objektov prikazov s parametrami.

Globalny DB kontext - tak ano, nemusel by som drzat ten kontext, stacili by mi mozno samotne objekty, ale zase ked sa nejake parametre v programe zmenia, potrebujem ten objekt ulozit, a bez povodneho kontextu to neurobim.

Moj pripad je desktop aplikacia a priamo pristupe k DB.

[Reakcia]

photo
liero
27. 9. 2017 17:40:55
Body: 9290
Najaktívnejší č.: 6

RE: LINQ to SQL DataContext strategia

Globalny DataContext je v tvojom pripade najhorsi mozny antipattern, aky si mohol urobit. Nielen kvoli memory leaku, ale aj kvoli multithreadingu.

  1. Co sa tyka memory leaku, musis si uvedomit jednu vec. DataContext si uklada vsetky entity, ktore selectnes, pripadne ich do DataContextu pridas. Napr.

    var productRows = dataContext.ProductRows.Where(...).ToArray();

    kopie selectnutych ProductRows su odteraz ulozene v datacontexte, aby ked zavolas niekedy v buducnosti SubmitChanges() datacontext vedel zistit, co sa zmenilo.

  2. Ak mas multithreading, kde kazdy thread bude pristupovat ku globalnemu datacontextu, tak sa ti stane, ze sa ti budu mixovat UnitOfWorky. Inak povedane zmeny z jedneho threadu ti moze submitnut iny thread v nevhodnom case.

Teraz skusim vyvratit nejaky myty:

  1. "Drzim si connection na databazu". No nedrzis :) Okrem toho toto vobec neries. Nema to s DataContextom nic spolocne.  ConnectionTimeout ti moze vyprsat tak ci tak, ak nic dlhsie nic nerobis a vtedy si LinqToSql vyrobi novy connection bez ohladu na to, ci si drzis, alebo nedrzis DataContext.

    Ak sa chces poistit, pouzi retry pattern. Niektore ORM to robia dokonca za teba.
  2. "Nemozem pouzit object (entitu) v inom DataContexte". Ale mozes. Musis ju tam akurat manualne pridat a povedat, ci ju ma novy DataContext chapat ako novu entitu (SubmitChanges vygeneruje INSERT), alebo zmenenu (UPDATE), alebo ako nezmenenu. Ale toto vobec netreba robit.


Vo vseobecnosti plati pravidlo, ze DataContext by si mal drzat co najkratsie. 

tu je priklad toho, ako mozes drzat nejake data globalne, ale Datacontext drzat co najkratsie. Mas nejake globalne settingy nacitane z databazy, ktore potrebujes obcas updatnut:

public class Settings
{
   public int Id {get; set;}
   public string Setting1 {get; set;}
   public string Setting2 {get; set;}
}

public static class MyGlobalContext
{
   public static  Settings SettingsInstance {get; private set; }
  
    public static void UpdateSettings(string setting1, string settting2)
    {
        using(var db = new MyDataContext())
        {
             var setting = db.Settings.FirstOrDefault(s => s.Id == SettingsInstance.Id);
             setting.Setting1 = setting1;
             setting.Setting2 = setting2;
             db.SubmitChanges();
             SettingsInstance = setting;
        }
    }
}
 

DataContext ma zmysel drzat dlhsie iba vtedy, ked chces trackovat zmeny, ktore chces potom submitnut naraz. Napriklad nejaky datagrid, kde uzivatel moze pridavat/editovat/mazat riadky a vsetko potom ulozit jednym tlacitkom. Vtedy mozes pouzit DataContext na trackovanie zmien v tom datagride a vsetk to submitnut ako jeden unit of work. Ale jeden DataContext na jeden grid! 

Ale toto aj tak nieje tvoj pripad.

 

[Reakcia]

photo
mma
27. 9. 2017 22:46:38
Body: 25
Najaktívnejší č.: 237

RE: LINQ to SQL DataContext strategia

Ano, toho som si uz vedomy, ze globalny kontext nebolo najlepsie riesenie...

K bodom:
1. Ano, to viem. Vtedy som asi nad tym az tolko nerozmyslal alebo co, a az tak casto problem nevznikal. Na problem s jednym kontextom som narazil az ked vtedy program bezal 3 mesiace a ked som zacal rozmyslat nad tym, preco to parkrat spadlo kvoli multithreadingu.

2. Zrovna ten problem, co pises, mi nevznika, lebo v hlavnom threade sa iba obcas cosi nacita alebo zapise pri zmene parametrov, a druhy thread iba zapisuje, takze so submitmi nebol problem. Problem robi to, ze obcas sa stane, ze obidva sucasne chcu cosi nacitat a vtedy to spadne. Potom som zacal rozmyslat, ako to urobit lepsie, kadeco precital a zistil, ze to nerobim najlepsie.

K mytom:
1. No podla mna drzim :) Ja rucne vytvorim SqlConnection a to priradim DataContextu. To som robil preto, lebo pri vybere noveho typu zakladam novy kontext, a aby sa nemuselo otvarat nove spojenie. A tiez som mohol potom kontrolovat stav spojenia. Alebo aj v tomto pripade kontext po case zatvori spojenie, zapamata si connection string a zalozi nove ked treba? Okrem toho, ked mam vzdy aktivne spojenie, predpokladam ze zapis do DB prebehne okamzite, takze nemusim riesit zapisove operacie asynchronne (ten druhy thread je relativne casovo kriticky, komunikuje so zariadenim a je na druhej strane kontrolovany lifebitom).

2. Ano, to tiez viem. Ak tym myslis to, ze zavolat bud Attach alebo InsertOnSubmit, tak zrovna metodu Attach v tych viacerych blogoch, co som cital, moc neodporucali.

K tomu prikladu, ano, tak by sa to dalo. Pri tom sa mi zda ale zbytocne, ze preco mam znovu nacitavat objekt, ktory uz raz aj tak mam, a preco rucne prepisovat vsetky (alebo min vsetky zmenene) settingy. To by sa sice dalo vyriesit cez Attach, ale je to naozaj taky problem drzat si kontext k tomu objektu? Cele to riesenie ako si napisal mi pripada, ako by to bolo tak urobene jednoucelovo len preto, aby som nemusel drzat ten kontext. Ma aj iny vyznam to urobit takto? Mohol by som si drzat kontext k tomu aktivnemu objektu pre pripad zapisu zmien, a na ukladanie protokolov a vsetky ostatne operacie vzdy zalozit novy.

Zaver, tak taky pripad tiez mam, nad ktorym som rozmyslal ci to robim spravne, ale to sem nejdem teraz miesat.

[Reakcia]

photo
liero
28. 9. 2017 9:00:58
Body: 9290
Najaktívnejší č.: 6

RE: LINQ to SQL DataContext strategia

Ked rucne vyrobis SqlConnection, naco potom drzis DataContext? Protirecis si. Aj tak je to ale zbytocne.

Pozri sa, pri webovej aplikacii by si vytvaral datacontext pri kadom requeste, co moze byt kludne 100x za sekundu a ORM to zvlada v pohode.

Celkovo sa riadis prilis vela predpokladmi, ktore nemas overene. Najprv to nakod v sulade s tym, naco su jednotlive triedy urcene a co najjednoduchsie a potom ries optimalizacie.

Dohodnime sa, ze to nakodis tak, ze si budes datacontext vytvarat pri kazdej operacii. Ked budes mat problem s performance, prides sem znova.


Co sa tyka mojho prikladu, moze sa ti to zdat zbytocne. Ale predstav si, ze by ta entita mala ovela viac properties, no ty by si chcel v tejto metode updatovat iba tie 2 properties. Keby si si ju nenacital z databazy, tak by si pri submite prepisal vsetky property tym co mas v pamati. Predpoklad, ze to nevadi, sa ti moze lahko vypomstit. Alternativne by si mohol drzat datacontext len pre tuto jednu entitu....

[Reakcia]

photo
liero
29. 9. 2017 12:02:12
Body: 9290
Najaktívnejší č.: 6

RE: LINQ to SQL DataContext strategia

@mmt: dalo by sa to aj takto, len tu menis SettingInstance este skor ako mas istotu ze to je ulozene v DB:

public static class MyGlobalContext
{
   public static  Settings SettingsInstance {get; private set; }
   
    public static void UpdateSettings(string setting1, string settting2)
    {
        using(var db = new MyDataContext())
        {
             db.Settings.Attach(SettingInstance);
             SettingInstance.Setting1 = setting1;
             SettingInstance.Setting2 = setting2;
             db.SubmitChanges();
        }
    }
}

workaround by bol:

var settings = new Settings { Id = SettingInstance };
db.Settings.Attach(setting);
settings.Setting1 = setting1;
settings.Setting2 = setting2;
db.SubmitChanges();

SettingsInstance = settings;        




[Reakcia]



Najaktívnejší užívatelia
1. 37750 b. photo vlko
2. 21305 b. photo T
3. 15955 b. photo spigi
4. 15450 b. photo Anonymous
5. 11110 b. photo dudok
6. 9290 b. photo Liero
7. 6885 b. photo siro
8. 6245 b. photo slavof
9. 5355 b. photo duracellko
10. 4445 b. photo xxxmatko