2010-02-18 8 views
22

Czy ktoś może pochwalić się ich opinią na temat zalet/wad pomiędzy zawijaniem DataContext w instrukcji using, a nie w LINQ-SQL pod względem czynników takich jak wydajność, pamięć wykorzystanie, łatwość kodowania, co trzeba zrobić itdW LINQ-SQL, wrap DataContext jest instrukcją użycia - plusy

Aktualizacja: w jednej konkretnej aplikacji, doświadczyłem, że bez owijania DataContext wykorzystaniem bloku, ilość zużycia pamięci przechowywane na zwiększenie jak żywych obiektów nie zostały wydane dla GC. Jak w, w poniższym przykładzie, jeśli przechowuję odwołanie do listy q obiektu i jednostek dostępu q, tworzę wykres obiektów, który nie jest zwolniony dla GC.

DataContext z użyciem

using (DBDataContext db = new DBDataContext()) 
    { 
     var q = 
      from x in db.Tables 
      where x.Id == someId 
      select x; 

     return q.toList(); 
    } 

DataContext bez korzystania i utrzymywane przy życiu

DBDataContext db = new DBDataContext() 
    var q = 
     from x in db.Tables 
     where x.Id == someId 
     select x; 

    return q.toList(); 

Dzięki.

+2

Wygląda na duplikat: http://stackoverflow.com/questions/821574/c-linq-to-sql-should-datacontext-be-dposed-using-idisposable/821595 – devuxer

+0

Chciałbym poznać wpływ na pamięć. – hIpPy

+0

podobne do http://stackoverflow.com/questions/821574/c-linq-to-sql-should-datacontext-be-disposed-using-idisposable/821595, dzięki DanM. – hIpPy

Odpowiedz

12

Kontekst Data może być kosztowne w stosunku do innych rzeczy. Jednak jeśli skończysz i chcesz, aby połączenia były zamykane JAK NAJSZYBCIEJ, zrobi to, zwalniając wszelkie buforowane wyniki z kontekstu. Pamiętaj, że tworzysz to niezależnie od tego, w tym przypadku po prostu pozwalasz garbage collector'owi wiedzieć, że jest więcej darmowych rzeczy do pozbycia się.

DataContext jest obiektem o krótkim czasie użycia, należy go użyć, uzyskać jednostkę pracy, wyjść ... właśnie to robisz z użyciem.

tak więc zalety:

  • Szybsze zamknięte połączenia
  • zwolnić pamięć w Dispose (obiektów buforowanych w treści)

Minusem - więcej kodu? Ale to nie powinno zniechęcać, poprawnie używasz tutaj using.

Spójrz na odpowiedź firmy Microsoft: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe

Krótka wersja jeśli trzeba użyć using/.Dispose():

Krótka odpowiedź; Nie, nie trzeba, ale powinien ...

+2

Najwyraźniej słyszeliśmy różne rzeczy o złożoności tworzenia DataContext. –

+0

@James - Chociaż nie jest aż tak ciężki, ** w porównaniu z innymi rzeczami ** w mojej obecnej aplikacji jest to zdecydowanie najcięższy przedmiot do zwożenia, jest lekki, ale wciąż cięższy od przeciętnego obiektu. –

5

No To IDisposable, więc myślę, że nie jest to zły pomysł. Ludzie z MSFT powiedzieli, że sprawili, że DataContext jest tak lekki, jak to tylko możliwe, więc możesz tworzyć je bezmyślnie, więc prawdopodobnie nie zyskujesz zbyt wiele .....

+0

To jest odpowiedź, którą otrzymałem, gdy zadaję podobne pytanie w innym miejscu.Zasadniczo nie boli i może pomóc, ale prawdopodobnie nie. – mark123

+3

@ mark123: Tylko jeden wyjątek, wszystkie IDisposable, które tworzysz, używasz i kończą w ramach jednej metody, powinny być spożywane w bloku 'using'. W przeciwnym razie autorzy nie zdecydowaliby się na wdrożenie "IDisposable". –

+0

Zgadzam się. Zawsze staraj się robić to dobrze. Przechodziłem przez mały problem, gdy próbowałem wymyślić, jak używać bloku z użyciem kontenera IoC (Castle Windsor) do tworzenia instancji elementów z repozytorium. Podkreślając przy tym problemie powiedziano mi, że kontener IoC obsługuje Dispose(). Mam nadzieję, że to prawda, bo to naprawdę ma sens. – mark123

4

I zależy od złożoności Twoich Danych Warstwa. Jeśli każde połączenie jest prostym pojedynczym zapytaniem, wówczas każde połączenie może być opakowane w Użycie jak w twoim pytaniu i to byłoby w porządku.

Jeśli, z drugiej strony, warstwa danych może oczekiwać wielokrotnych wywołań sekwencyjnych z warstwy biznesowej, użytkownik powinien wielokrotnie uruchamiać/usuwać DataContext dla każdej większej sekwencji wywołań. nieidealny.

To, co zrobiłem, to utworzyć obiekt warstwy danych jako IDisposible. Po utworzeniu tworzony jest DataContext (lub tak naprawdę, po pierwszym wywołaniu metody), a gdy obiekt warstwy danych zostanie zutylizowany, to zamknie i zniesie DataContext.

oto jak to wygląda:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Configuration; 

namespace PersonnelDL 
{ 
    public class PersonnelData : IDisposable 
    { 
     #region DataContext management 
     /// <summary> 
     /// Create common datacontext for all data routines to the DB 
     /// </summary> 
     private PersonnelDBDataContext _data = null; 
     private PersonnelDBDataContext Data 
     { 
      get 
      { 
       if (_data == null) 
       { 
        _data = new PersonnelDBDataContext(ConfigurationManager.ConnectionStrings["PersonnelDB"].ToString()); 
        _data.DeferredLoadingEnabled = false; // no lazy loading 
        //var dlo = new DataLoadOptions(); // dataload options go here 
       } 
       return _data; 
      } 
     } 

     /// <summary> 
     /// close out data context 
     /// </summary> 
     public void Dispose() 
     { 
      if (_data != null) 
       _data.Dispose(); 
     } 
     #endregion 

     #region DL methods 
     public Person GetPersonByID(string userid) 
     { 
      return Data.Persons.FirstOrDefault(p => p.UserID.ToUpper().Equals(userid.ToUpper())); 
     } 

     public List<Person> GetPersonsByIDlist(List<string> useridlist) 
     { 
      var ulist = useridlist.Select(u => u.ToUpper().Trim()).ToList(); 
      return Data.Persons.Where(p => ulist.Contains(p.UserID.ToUpper())).ToList(); 
     } 

     // more methods... 
     #endregion 
    } 
} 
1

W jednej konkretnej aplikacji, doświadczyłem, że bez owijania DataContext w using blok, ilość zużycia pamięci przechowywane na zwiększenie jak żywe obiekty nie zostały dopuszczone do GC. Tak jak w, w poniższym przykładzie, jeśli przechowuję odwołanie do obiektu List<Table> i jednostek dostępu o numerze q, tworzę wykres obiektów, który nie jest wydany dla GC.

DBDataContext db = new DBDataContext() 
var qs = 
    from x in db.Tables 
    where x.Id == someId 
    select x; 

return qs.toList(); 

foreach(q in qs) 
{ 
    process(q); 
    // cannot dispose datacontext here as the 2nd iteration 
    // will throw datacontext already disposed exception 
    // while accessing the entity of q in process() function 
    //db.Dispose(); 
} 

process(Table q) 
{ 
    // access entity of q which uses deferred execution 
    // if datacontext is already disposed, then datacontext 
    // already disposed exception is thrown 
} 

Biorąc pod uwagę ten przykład, nie mogę wyrzucać DataContext ponieważ wszystkie Table przypadki, w liście zmiennej qs ** podziela tą datacontext. Po Dispose(), dostęp do obiektu w process(Table q) powoduje zgłoszenie datacontekstu już z wyjątkiem wyjątku.

Brzydkim klusem było dla mnie usunięcie wszystkich odwołań encji dla q obiektów po pętli foreach. Lepszym sposobem jest oczywiście użycie instrukcji using.

Jeśli chodzi o moje doświadczenie, powiedziałbym, że należy użyć oświadczenia using.

5
  1. Po raz pierwszy DataContext otrzyma obiekt z bazy danych.
  2. Następnym razem, gdy odpalisz zapytanie, aby uzyskać ten sam obiekt (te same parametry): zobaczysz zapytanie w profilerze, ale twój obiekt w DataContext nie zostanie zastąpiony nowym z DB !!

Nie wspominając, że za każdym DataContext jest mapa tożsamości wszystkich obiektów, o które pytasz z DB (nie chcesz tego utrzymywać).

Cały pomysł DataContext jest jednostka pracy z optymistycznych założeniach równoczesności. Użyj go do krótkiej transakcji (tylko jedna przesyłka) i wyrzuć.

Najlepszym sposobem, aby nie zapominać o dysponowaniu, jest używanie().