ASP.NET MVC - czy jest sens zwalniac polaczenie z baza danych?

0

Bazując na tym artykule: http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application użyłem wzorca repository i unit of work. Jednak zastanawia mnie czy jest sens pisania metod dispose, które będą zwalniać połączenie z bazą danych? W istniejących projektach nie widziałem nigdzie żeby ktoś dbał o zwalnianie połączenia z bazą danych.

W moim projekcie w kontrolerach używam serwisów i wywołuję metodę dispose - nadpisując ją, w której z kolei są wywoływane metody dispose użytych serwisów:

 
    public class BlogController : Controller
    {        
        private readonly INotesService _notesService;        
          
        public BlogController(INotesService notesService)
        {
            _notesService = notesService;
        }
    
    
        protected override void Dispose(bool disposing)
        {
            _notesService.Dispose();
            base.Dispose(disposing);
        }
    }

W serwisach w metodzie dispose wywołuję metodę dispose klasy unit of work:

public class NotesService : INotesService
{
    private readonly IUnitOfWork _unitOfWork;

    public NotesService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }


    public void Dispose()
    {
        _unitOfWork.Dispose();
    }
}
 

A w klasie unit of work metoda dispose zwalnia połączenie z bazą danych:

 
public class UnitOfWork : IUnitOfWork
{
    private DatabaseContext context = new DatabaseContext();
    private INotesRepository notesRepository;

    public INotesRepository NotesRepository
    {
        get
        {
            if (this.notesRepository == null)
            {
                this.notesRepository = new NotesRepository(context);
            }
            return notesRepository;
        }
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                this.context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Więc w każdym kontrolerze nadpisuję metodę dispose, w której wywołuję metody dispose tych serwisów, których używam w danym kontrolerze.

0

Nikt nie dba o zwalnianie ponieważ to się samo dzieje, czy dbasz o niszczenie obiektów w pamięci po zakończeniu działania Twojej aplikacji? wątpię. tak samo jest tutaj.
Czy oby na pewno wiesz po co jest ten unit of work?
za każdym razem kiedy chcesz wykonać operacje na bazie danych to BEZ unitOfWork wyglądało by to tak: zapytanie leci do bazy, zmiana, ok; inny scenariusz: zapytanie leci do DB, upps coś nie tak, zostaje Ci błąd i otwarte połączenie ;] to raz, a dwa, jeśli chcesz zmienić dwie tabele które są jakoś połączone w bazie to wtedy skrypty SQL będą kiepsko wygenerowane, natomiast dzięki transakcjom ładnie wszystko przejdzie ponieważ całe Twoje zapytanie jest pakowane i dopiero wykonywane - dopóki nie zrobisz COMITT to w bazie nic się nie zmieni. poza tym nie wiem po co w sumie w kontrolerze pisać Dispose :)

tak wygląda mój Unit:

 

   public class UnitOfWork: IUnitOfWork
    {
        private readonly ISession session;
        private ITransaction transaction;
        bool disposed = false;

        public UnitOfWork(ISession session)
        {
            this.session = session;
            this.transaction = session.BeginTransaction();
        }

        public void Committ()
        {
            if (!this.transaction.IsActive)
            {
                throw new Exception();
            }

            this.transaction.Commit();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool a)
        {
            if (disposed)
                return;
            if (a)
            {
                this.transaction.Dispose();
                this.transaction = null;
            }
            disposed = true;
        }

        ~UnitOfWork()
        {
            Dispose(false);
        }
    }
0

O dzięki, czyli wystarczy dodać destruktor w klasie unit of work i nie będę musiał robić dispose w kontrolerach - dzięki !!

0

@up
Koledze ne0 chyba chodzilo, ze czesto wzorzec UnitOfWork jest na dwa sposoby przedstawiany, standardowo

interface IUnitOfWork {
void Commit();
}

Prosze o polaczenie watkow, gdyz przez przypadek gorny post mi sie zatwierdzil

Lub w ten sposob:

interface IUnitOfWork {
void Commit();
IUserRepository UserRepository {get;}
IJakiesTamRepository JakiesTamRepository {get;set;}
.....
}

Czyli UnitOfWork grupuje wszystkie uzywane repozytoria.

1

Tak wygląda UoW: http://martinfowler.com/eaaCatalog/unitOfWork.html

Wsadzanie tam repozytoriów, sprawia, że przestaje być UoW, a zaczyna być gwałtem na SOLID.

0

@somekind - nie zgodzę się, wystarczy spojrzeć na tutorial Microsoftu: http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
tam własnie w klasie unit of work są inicjowane repozytoria.

0

To, ze Microsoft cos pokazuje, nie znaczy wcale, ze to ma sens.

UoW z definicji zarzadza obiektami 'dotchnietymi' transakcja. Nie ma pojecia o zadnej logice biznesowej, tylko sluzy do persystencji zmian w 1 miejscu - przy commicie, badz ich wycofaniu. Natomiast repozytoria (te konretne typu ProductsRepository) zawieraja logike biznesowa, po to je sie w ogole pisze. Jesli by mialo w nich nie byc zadnej logiki, to nikt by sobie glowy nie zawracal, zeby robic N klas, gdzie wszystko mozna wepchnac do 1 generycznej...

W kwestii praktycznej, sens pisania UoW (a wlasciwie to przelotki nad gotowa implementacja typu https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/ISession.cs) jest dosc niski w 99% przypadkow. Jedyne co jest sens pisac to wrapper na sesje i transakcje, ktora jest odpalana w konstruktorze i zwalniana w Dispose() co troche ulatwia wstrzykiwanie tego per HttpRequest.

0

no to ja sprecyzuje o co mi chodziło. Mianowicie aby mieć jeden plik o nazwie Repositories. w którym to mam repozytoria + funkcję committ UnitOfWork. Dzięki temu w kontrolerze (czy to asp.net mvc, webapi no whatever) wstrzykuje jedno repozytorium a nie np. 4 +unit of work ;]
potem sobie robię:
repositories.users.add(newUser)
repositories.cars.add(newCar)
repositories.committ();

0
 namespace NhOrm.Repositories
{
    using System;

    using Domain.Abstract.Repositories;

    using NHibernate;

    public class Repositories : Domain.Abstract.Repositories.Repositories
    {
        private readonly ISession session;

        private ITransaction transaction;

        private bool disposed;

        public Repositories(ILoungeOpeningTimeRepository openingTimeRepository,IPassangerRepository passangerRepository, ICreditRepository creditRepository, ILoungeRepository loungeRepository, IExtraRepository extraRepository, ISession session, IPriceRepository priceRepository, IOrderRepository orderRepository)
            : base(openingTimeRepository,passangerRepository,creditRepository,loungeRepository, extraRepository, priceRepository, orderRepository)
        {
            this.session = session;
            this.transaction = session.BeginTransaction();
        }

        public override void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed && disposing)
            {
                if (this.transaction != null)
                {
                    this.transaction.Dispose();
                    this.transaction = null;
                }

                this.disposed = true;
            }
        }

        public override void Commit()
        {
            if (this.transaction == null)
                throw new InvalidOperationException("Transaction already completed");
            
            this.transaction.Commit();
            this.transaction = null;
        }
    }
}
 namespace Domain.Abstract.Repositories
{
    public abstract class Repositories : IUnitOfWork
    {
        public Repositories(ILoungeOpeningTimeRepository loungeOpeningTimeRepository, IPassangerRepository passangerRepository,  ICreditRepository creditRepository, ILoungeRepository loungeRepository, IExtraRepository extraRepository, IPriceRepository priceRepository, IOrderRepository orderRepository)
        {
            this.Lounges = loungeRepository;
            this.Extras = extraRepository;
            this.Prices = priceRepository;
            this.Orders = orderRepository;
            this.LoungeOpeningTimes = loungeOpeningTimeRepository;
            this.Credits = creditRepository;
            this.Passengers = passangerRepository;
        }

        public abstract void Dispose();

        public abstract void Commit();

        public ILoungeRepository Lounges { get; private set; }

        public IPassangerRepository Passengers { get; private set; }

        public IExtraRepository Extras { get; private set; }

        public ICreditRepository Credits { get; private set; }

        public IPriceRepository Prices { get; private set; }

        public IOrderRepository Orders { get; private set; }

        public ILoungeOpeningTimeRepository LoungeOpeningTimes { get; private set; }
    }
}
0
pytk napisał(a):

@somekind - nie zgodzę się, wystarczy spojrzeć na tutorial Microsoftu: http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
tam własnie w klasie unit of work są inicjowane repozytoria.

Z tutoriali Microsoftu wynika również, żeby logikę biznesową implementować w kontrolerach, i w ogóle nie używać repozytoriów, tylko operować bezpośrednio na DbContext.

To, że Micorosoft wpadł na genialny inaczej pomysł zespawania ze sobą "generycznych repozytoriów" oraz UoW, i nazwał to DbContext, nie znaczy jeszcze, że to ma sens. Moim zdaniem, wyszła im niezła kupa, NHibernate pod względem konstrukcji jest bardziej przejrzysty niż EF.

ne0 napisał(a):

no to ja sprecyzuje o co mi chodziło. Mianowicie aby mieć jeden plik o nazwie Repositories. w którym to mam repozytoria + funkcję committ UnitOfWork. Dzięki temu w kontrolerze (czy to asp.net mvc, webapi no whatever) wstrzykuje jedno repozytorium a nie np. 4 +unit of work ;]
potem sobie robię:
repositories.users.add(newUser)
repositories.cars.add(newCar)
repositories.committ();

Jeśli w każdej klasie potrzebujesz wszystkich czterech repozytoriów, to dlaczego masz cztery, a nie jedno?
Jeśli tak nie jest, to dlaczego chcesz dawać jakimś klasom dostęp do tego, czego nie potrzebują?

Jedno jest pewne - zrobiłeś coś nowego i niespotykanego nigdzie na świecie. ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1