Skocz do zawartości

[Sfera] Usuwanie pozycji z cenników dodatkowych "OutOfMemory"

Polecane posty

Mam w rozwiązaniu sferycznym jedną funkcję, która tworzy dodatkowy asortyment, a właściwie usługę, na podstawie innego asortymentu. Częścią tego procesu, jest usunięcie zbędnych informacji związanych z asortymentem, między innymi wywalenie go z cenników dodatkowych, jeśli się znajduje. Robię to takim kodem:

foreach (Cennik dodatkowy in usluga.Dane.PozycjeCennika.Select(p => p.Cennik).Distinct()) {
        ICennik dodatkowyBo = cenniki.Znajdz(dodatkowy);
        foreach (IUproszczonaPozycjaCennika uprPozCen in dodatkowyBo.Pozycje.Wszystkie.Where(p => p.IdAsortymentu == usluga.Dane.Id)) dodatkowyBo.Pozycje.Usun(uprPozCen);
        if(!dodatkowyBo.Zapisz()) dodatkowyBo.WypiszBledy();
        }

Dzisiaj, dostałem taki oto błąd:

System.OutOfMemoryException: Zgłoszono wyjątek typu 'System.OutOfMemoryException'.
   w lambda_method(Closure , Shaper )
   w System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
   w System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
   w System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   w System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   w System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   w InsERT.Moria.CennikiICeny.KoordynatorUproszczonychPozycjiCennika.UtworzUproszczonePozycjeInternal(IQueryable`1 query)
   w InsERT.Moria.CennikiICeny.KoordynatorUproszczonychPozycjiCennika.UtworzUproszczonePozycje(IQueryable`1 query)
   w InsERT.Moria.Narzedzia.KoordynatorUproszczonychPozycji`4.PodajPozycje()
   w InsERT.Moria.CennikiICeny.CennikBO.InsERT.Moria.CennikiICeny.ICennikPozycje.get_Wszystkie()
   w SynchronousSocketListener.StartListening()

Całkiem możliwe, że wczytywanie takie zakresu danych sprawia problem dla pamięci, bo mamy sporo produktów, przewinęło się też sporo cenników. Metoda była skonstruowana w sumie w 2017 roku, na podstawie tego postu:

W międzyczasie, cenniki się zmieniły, więc może można to zrobić lepiej? ;)

Link to postu

Po pierwsze brakuje tam using'a więc po zapisie każdego obiektu "dodatkowyBO" nie są zwalniane zasoby przez niego zajęte. Po drugie warto byłoby w tej pętli odfiltrować TYLKO cenniki dodatkowe (na podstawie pola Bazowy encji Cennik). W tym przypadku dla cenników głównych nadmiarowo będzie wykonywana operacja usuwająca pozycje, która i tak nie ma szans zadziałać (cennik główny musi mieć wszystkie pozycje z kartoteki). Po trzecie zamiast ładować wszystkie uproszczone pozycje można wykorzystać metodę ICennikPozycje.ZnajdzPozycjeCennika(Asortyment asortyment), która pobierze nam TYLKO pozycje związane z podanym asortymentem.

Ewentualnie można byłoby spróbować zamiast ładować cały cennik wykorzystać menedżer pozycji cennika (IPozycjeCennika) załadować interesujące nas pozycje (IPozycjaCennika) i je usunąć omijając w ogóle obiekt biznesowy cennika (ICennik), ale to wymagałoby już większej przeróbki tego kodu.

Link to postu

No dobra, to zobaczymy, czy dobrze załapałem sugestie :)

4 godziny temu, Wojciech Szopiński napisał:

Po pierwsze brakuje tam using'a więc po zapisie każdego obiektu "dodatkowyBO" nie są zwalniane zasoby przez niego zajęte.

using(ICennik dodatkowyBo = cenniki.Znajdz(dodatkowy))
4 godziny temu, Wojciech Szopiński napisał:

Po drugie warto byłoby w tej pętli odfiltrować TYLKO cenniki dodatkowe (na podstawie pola Bazowy encji Cennik).

foreach (Cennik dodatkowy in usluga.Dane.PozycjeCennika.Select(p => p.Cennik).Distinct().Where(c => c.Bazowy == false))
4 godziny temu, Wojciech Szopiński napisał:

Po trzecie zamiast ładować wszystkie uproszczone pozycje można wykorzystać metodę ICennikPozycje.ZnajdzPozycjeCennika(Asortyment asortyment), która pobierze nam TYLKO pozycje związane z podanym asortymentem.

ICennikPozycje pozycjeCennika = dodatkowyBo.Pozycje;
var uslugaDoUsuniecia = asortymenty.Dane.Wszystkie().Where(a => a.Id == usluga.Dane.Id).FirstOrDefault();
foreach(var pozycja in pozycjeCennika.ZnajdzPozycjeCennika(uslugaDoUsuniecia)) dodatkowyBo.Pozycje.Usun(pozycja);

Swoją drogą, szkoda, że WypelnijNaPodstawie dla asortymentu, nie może pominąć kopiowania cenników, bo usuwanie tych pozycji z cennika trwa bardzo długo. Dlatego też w ostatecznej wersji Swojego kodu, pominąłem cenniki, które są zamknięte - ryzyko ponownego otwarcia w mojej organizacji jest znikome, więc można zaryzykować.

Ostatecznie, kod wygląda tak - jest ok (to wtedy wrzucę nową wersję do tamtego postu, może komuś pomoże).

      foreach (Cennik dodatkowy in usluga.Dane.PozycjeCennika.Select(p => p.Cennik).Distinct().Where(c => c.Bazowy == false && c.Status != 2)) {
      	using(ICennik dodatkowyBo = cenniki.Znajdz(dodatkowy))
      	  {
      	  Console.WriteLine("Cennik: "+dodatkowyBo.Dane.Tytul);
      	  ICennikPozycje pozycjeCennika = dodatkowyBo.Pozycje;
      	  var uslugaDoUsuniecia = asortymenty.Dane.Wszystkie().Where(a => a.Id == usluga.Dane.Id).FirstOrDefault();
      	  foreach(var pozycja in pozycjeCennika.ZnajdzPozycjeCennika(uslugaDoUsuniecia)) 
      	    {
      	    Console.WriteLine("Usuwanie pozycji: "+pozycja.Id+"/"+pozycja.CenaBazowa);
      	    dodatkowyBo.Pozycje.Usun(pozycja);	
      	    }
          if(!dodatkowyBo.Zapisz()) dodatkowyBo.WypiszBledy();
      	  }
        }

 

Link to postu
×
×
  • Dodaj nową pozycję...