Entity Framework i kontekst wywołania.usunąć()

Kiedy należy wywołać {[3] } z entity framework?

  1. Czy ta wyimaginowana metoda jest zła?

    public static string GetName(string userId)
    {
        var context = new DomainDbContext();
        var userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
        context.Dispose();
        return userName;
    }
    
  2. Tak lepiej?

    public static string GetName(string userId)
    {
        string userName;
        using(var context = new DomainDbContext()) {
            userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
            context.Dispose();
        }
        return userName;
    }
    
  3. Czy to jeszcze lepiej, to znaczy, jeśli nie nazwać kontekstu.Dispose () podczas używania using ()?

    public static string GetName(string userId)
    {
        string userName;
        using(var context = new DomainDbContext()) {
            userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
        }
        return userName;
    }
    
Author: TylerH, 2013-03-27

6 answers

W rzeczywistości są to dwa pytania w jednym:

  1. Kiedy powinienem Dispose() z kontekstu?
  2. Jaka powinna być długość życia mojego kontekstu?

Odpowiedzi:

  1. Nigdy 1. using jest implicit Dispose() w bloku try-finally. Oddzielna Instrukcja Dispose może zostać pominięta, gdy wyjątek wystąpi wcześniej. Ponadto, w większości przypadków, nie wywołanie Dispose w ogóle (w sposób dorozumiany lub jawny) nie jest szkodliwy .

  2. Zobacz np. Entity Framework 4 - długość życia / zakres kontekstu w aplikacji winform . Krótko mówiąc: długość życia powinna być "krótka", statyczny kontekst jest zły.


1 jak niektórzy komentowali, wyjątek od tej reguły stanowi sytuacja, gdy kontekst jest częścią komponentu, który implementuje IDisposable sam i dzieli swój cykl życia. W takim przypadku wywołałbyś context.Dispose() w metodzie Dispose komponentu.

 107
Author: Gert Arnold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-16 20:22:12

Śledziłem kilka dobrych tutoriali do korzystania z EF i nie pozbywają się kontekstu.

Byłem trochę ciekaw tego i zauważyłem, że nawet szanowany Microsoft VIP nie pozbywa się kontekstu. Odkryłem, że nie musisz pozbywać się dbContext w normalnej sytuacji.

Jeśli chcesz więcej informacji, możesz przeczytać ten wpis na blogu , który podsumowuje dlaczego.

 38
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-03 16:43:13

Jeszcze lepiej:

public static string GetName(string userId)
{
    using (var context = new DomainDbContext()) {
        return context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
    }
}

Nie ma potrzeby zwracania wyniku spoza zakresu using; po prostu zwróć go natychmiast, a nadal uzyskasz pożądane zachowanie usuwania.

 16
Author: Todd Menier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-16 20:03:31

Możesz zdefiniować kontekst bazy danych jako pole klasy i zaimplementować IDisposable. Coś jak poniżej:

public class MyCoolDBManager : IDisposable
{
    // Define the context here.
    private DomainDbContext _db;

    // Constructor.
    public MyCoolDBManager()
    {
        // Create a new instance of the context.
        _db = new DomainDbContext();
    }

    // Your method.
    public string GetName(string userId)
    {           
        string userName = _db.UserNameItems.FirstOrDefault(x => x.UserId == userId);

        return userName;
    } 

    // Implement dispose method.
    // NOTE: It is better to follow the Dispose pattern.
    public void Dispose()
    {
         _db.dispose();
         _db = null;
    }
}
 2
Author: A-Sharabiani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-31 12:28:04

Jak wspomniał Daniel, nie musisz pozbywać się dbContext.

Z Artykułu:

mimo że implementuje IDisposable, implementuje go tylko po to, aby można było nazwać Disposable jako zabezpieczenie w niektórych szczególnych przypadkach. Domyślnie DbContext automatycznie zarządza połączeniem.

Więc:

public static string GetName(string userId) =>
    new DomainDbContext().UserNameItems.FirstOrDefault(x => x.UserId == userId);
 1
Author: dimaaan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-15 15:34:01

Można chcieć pozbyć się kontekstu w niektórych przypadkach.

W uproszczeniu przykładu OP wystarczy słowo kluczowe using.

Więc kiedy musimy użyć dispose?

Spójrz na ten scenariusz: musisz przetworzyć duży plik, komunikację lub umowę o świadczenie usług internetowych, która wygeneruje setki lub tysiące rekordów BD.

Dodawanie (+400) tysięcy lub setek encji w EF jest uciążliwe dla wydajności: kwestia wydajności w ramach encji, saveChanges jest bardzo wolno

Rozwiązanie jest opisane bardzo dobrze na tej stronie: https://entityframework.net/improve-ef-add-performance

TL; DR-zaimplementowałem to i tak skończyłem z czymś takim:

    /// <summary>
    /// Convert some object contract to DB records
    /// </summary>
    /// <param name="objs"></param>
    public void SaveMyList(WCF.MyContract[] objs)
    {
        if (objs != null && objs.Any())
        {
            try
            {
                var context = new DomainDbContext();
                try
                {
                    int count = 0;
                    foreach (var obj in objs)
                    {
                        count++;

                        // Create\Populate your object here....
                        UserNameItems myEntity = new UserNameItems();

                        ///bla bla bla

                        context.UserNameItems.Add(myEntity);

                        // https://entityframework.net/improve-ef-add-performance
                        if (count % 400 == 0)
                        {
                            context.SaveChanges();
                            context.Dispose();
                            System.Threading.Thread.Sleep(0); // let the system breathe, other processes might be waiting, this one is a big one, so dont use up 1 core for too long like a scumbag :D
                            context = new DomainDbContext();
                        }
                    }

                    context.SaveChanges();
                }
                finally
                {
                    context.Dispose();
                    context = null;
                }

                Log.Info("End");
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("{0}-{1}", "Ups! something went wrong :( ", ex.InnerException != null ? ex.InnerException.ToString() : ex.Message), ex);
                throw ex;
            }
        }
    }
 0
Author: Gotham Llianen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-11 11:47:41