Po co używać "wirtualnego" dla właściwości klasy w definicjach modelu encji Framework?

Na blogu: http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

Blog zawiera przykładowy kod:

public class Dinner
{
   public int DinnerID { get; set; }
   public string Title { get; set; }
   public DateTime EventDate { get; set; }
   public string Address { get; set; }
   public string HostedBy { get; set; }
   public virtual ICollection<RSVP> RSVPs { get; set; }
}

public class RSVP
{
   public int RsvpID { get; set; }
   public int DinnerID { get; set; }
   public string AttendeeEmail { get; set; }
   public virtual Dinner Dinner { get; set; }
}

Jaki jest cel używania virtual przy definiowaniu właściwości w klasie? Jaki to ma efekt?

Author: jps, 2011-12-17

7 answers

Pozwala Frameworkowi Entity na tworzenie proxy wokół wirtualnej właściwości, dzięki czemu właściwość może obsługiwać leniwe ładowanie i bardziej efektywne śledzenie zmian. Zobacz jaki efekt może mieć słowo kluczowe wirtualne w kodzie Entity Framework 4.1 POCO? do bardziej szczegółowej dyskusji.

Edit to clear "create a proxy around": Przez "Utwórz proxy wokół" mam na myśli konkretnie to, co robi Framework Entity. Struktura Entity wymaga Twojej nawigacji właściwości, które mają być oznaczone jako wirtualne, dzięki czemu obsługiwane są leniwe ładowanie i efektywne śledzenie zmian. Zobacz wymagania dotyczące tworzenia Proxy POCO .
Struktura Entity wykorzystuje dziedziczenie do obsługi tej funkcjonalności, dlatego wymaga, aby pewne właściwości były oznaczone jako wirtualne w klasie bazowej POCOs. Dosłownie tworzy nowe typy, które pochodzą z Twoich typów POCO. Więc twoje POCO działa jako typ bazowy dla dynamicznie tworzonych podklas encji. That ' s what I przez "Utwórz proxy wokół".

Dynamicznie tworzone podklasy, które tworzy struktura encji, stają się widoczne podczas używania struktury encji w czasie wykonywania, a nie w czasie kompilacji statycznej. I tylko wtedy, gdy włączysz funkcje leniwego ładowania lub śledzenia zmian w ramach encji. Jeśli zdecydujesz się nigdy nie korzystać z funkcji leniwego ładowania lub śledzenia zmian w ramach encji (która nie jest domyślna), nie musisz deklarować żadnych właściwości nawigacji jako wirtualne. Jesteś wtedy odpowiedzialny za ładowanie tych właściwości nawigacji samodzielnie, albo za pomocą tego, co Framework Entity określa jako "eager loading", lub ręczne pobieranie powiązanych typów w wielu zapytaniach do bazy danych. Możesz i powinieneś używać leniwych funkcji ładowania i śledzenia zmian dla właściwości nawigacji w wielu scenariuszach.

Jeśli utworzysz samodzielną klasę i oznaczysz właściwości jako wirtualne, a po prostu skonstruujesz i użyjesz instancji tych klas we własnej aplikacji, całkowicie poza zakresem struktury encji, Twoje wirtualne właściwości nie przyniosłyby ci niczego na własną rękę.

Edytuj, aby opisać, dlaczego właściwości mają być oznaczone jako wirtualne

Właściwości takie jak:

 public ICollection<RSVP> RSVPs { get; set; }

Nie są polami i nie powinny być traktowane jako takie. Są one nazywane getterami i setterami i w czasie kompilacji są konwertowane na metody.

//Internally the code looks more like this:
public ICollection<RSVP> get_RSVPs()
{
    return _RSVPs;
}

public void set_RSVPs(RSVP value)
{
    _RSVPs = value;
}

private RSVP _RSVPs;

Dlatego są oznaczone jako wirtualne do użytku w ramach encji, to pozwala dynamicznie tworzonym klasom nadpisywać wewnętrznie generowane funkcje get i set. Jeśli twoja właściwość nawigacyjna getter / setters działa dla Ciebie w używaniu struktury encji, spróbuj zmienić je do właściwości, przekompiluj i sprawdź, czy struktura encji nadal działa poprawnie:

 public virtual ICollection<RSVP> RSVPs;
 266
Author: Shan Plourde,
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
2017-05-23 10:31:31

Słowo kluczowe virtual W C# umożliwia nadpisanie metody lub właściwości przez klasy potomne. Aby uzyskać więcej informacji, zapoznaj się z dokumentacją MSDN dotyczącą słowa kluczowego "virtual"

UPDATE: to nie odpowiada na pytanie, jak obecnie zadane, ale zostawię je tutaj dla każdego, kto szuka prostej odpowiedzi na original , nieopisowe pytanie zadane.

 78
Author: M.Babcock,
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-11-15 13:23:33

Rozumiem frustrację OPs, to użycie virtual nie jest dla szablonowej abstrakcji, dla której DeFacto virtual modyfikator jest skuteczny.

Jeśli ktoś nadal się z tym boryka, to proponuję swój punkt widzenia, ponieważ staram się ograniczyć do minimum rozwiązania i żargon:

Entity Framework w prostym kawałku wykorzystuje leniwe ładowanie, co jest odpowiednikiem przygotowania czegoś do przyszłego wykonania. Pasuje do modyfikatora "wirtualnego", ale jest coś więcej do to.

W Entity Framework, korzystanie z właściwości virtual navigation pozwala określić go jako odpowiednik nullable Foreign Key w SQL. Nie musisz chętnie dołączać do każdej tabeli z kluczami podczas wykonywania zapytania, ale gdy potrzebujesz informacji-staje się ona zależna od popytu.

Wspomniałem również o nullable, ponieważ wiele właściwości nawigacji na początku nie jest istotnych. czyli w scenariuszu klient / zamówienia nie musisz czekać do momentu realizacji zamówienia do stwórz klienta. Możesz, ale jeśli miałeś wieloetapowy proces, aby to osiągnąć, możesz znaleźć potrzebę persist Danych Klienta do późniejszego zakończenia lub wdrożenia do przyszłych zamówień. Gdyby wszystkie właściwości nav zostały zaimplementowane, musiałbyś ustanowić każdy klucz obcy i pole relacyjne na zapisie. To naprawdę po prostu ustawia dane z powrotem do pamięci, co pokonuje rolę trwałości.

Więc chociaż może się wydawać tajemnicze w rzeczywistym wykonaniu w czasie wykonywania, mam najlepszą zasadą jest: jeśli przesyłasz dane (wczytujesz do modelu widoku lub modelu Serializowalnego) i potrzebujesz wartości przed referencjami, nie używaj wirtualnych; jeśli twój zakres zbiera dane, które mogą być niekompletne lub wymagają wyszukiwania i nie wymagają każdego parametru wyszukiwania ukończonego dla wyszukiwania, kod będzie dobrze wykorzystywać referencję, podobnie jak przy użyciu nullable value properties int? długo?. Również, abstrakcji logiki biznesowej z gromadzenia danych, aż do konieczności inject it ma wiele zalet wydajności, podobnych do tworzenia instancji obiektu i uruchamiania go od null. Entity Framework wykorzystuje wiele refleksji i dynamiki, które mogą obniżyć wydajność, a potrzeba posiadania elastycznego modelu, który może skalować się w zależności od zapotrzebowania, ma kluczowe znaczenie dla zarządzania wydajnością.

Dla mnie to zawsze miało większy sens niż używanie przeciążonego żargonu technologicznego, takiego jak Proxy, delegaci, handlerzy i tym podobne. Gdy trafisz na trzeci lub czwarty język programowania, może się to skomplikować to.

 22
Author: Nathan Teague,
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-02-19 01:15:01

Dość powszechne jest definiowanie właściwości nawigacyjnych w modelu do bądź wirtualny. Gdy właściwość nawigacji jest zdefiniowana jako wirtualna, może skorzystaj z pewnych funkcjonalności Entity Framework. Na najczęściej jest to leniwe Ładowanie.

Leniwe ładowanie jest miłą cechą wielu ORM-ów, ponieważ pozwala na dynamiczny dostęp do powiązanych danych z modelu. Nie będzie niepotrzebnie pobierać powiązane dane, dopóki nie zostaną one faktycznie udostępnione, w ten sposób redukcja z przodu wyszukiwanie danych z bazy danych.

Z książki "ASP.NET MVC 5 z Bootstrap i nokaut.js "

 16
Author: Hassan Rahman,
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
2016-03-02 07:52:38

W kontekście EF, zaznaczenie właściwości jako virtual pozwala EF użyć leniwego ładowania, aby ją załadować. W przypadku leniwego ładowania EF musi utworzyć obiekt proxy, który nadpisuje właściwości wirtualne implementacją, która ładuje obiekt odniesienia, gdy jest on po raz pierwszy dostępny. Jeśli nie oznaczysz właściwości jako wirtualną, leniwe ładowanie nie będzie z nią działać.

 10
Author: Shakeer Hussain,
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-02-27 07:58:36

Wirtualne słowo kluczowe jest używane do modyfikacji metody, właściwości, indeksatora lub deklaracji zdarzenia i pozwala na nadpisanie jej w klasie pochodnej. Na przykład, ta metoda może być nadpisana przez dowolną klasę, która ją dziedziczy:

public virtual double Area() 
{
    return x * y;
}

Nie można używać modyfikatora wirtualnego z modyfikatorami statycznymi, abstrakcyjnymi, prywatnymi lub nadpisującymi. Poniższy przykład pokazuje wirtualną Właściwość:

class MyBaseClass
{
    // virtual auto-implemented property. Overrides can only
    // provide specialized behavior if they implement get and set accessors.
    public virtual string Name { get; set; }

    // ordinary virtual property with backing field
    private int num;
    public virtual int Number
    {
        get { return num; }
        set { num = value; }
    }
}


class MyDerivedClass : MyBaseClass
{
    private string name;

    // Override auto-implemented property with ordinary property
    // to provide specialized accessor behavior.
    public override string Name
    {
        get
        {
            return name;
        }
        set
        {
            if (value != String.Empty)
            {
                name = value;
            }
            else
            {
                name = "Unknown";
            }
        }
    }
}
 0
Author: FatalMan,
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-04-12 14:26:52

Nie możemy mówić o wirtualnych członkach bez odniesienia się do polimorfizmu . W rzeczywistości funkcja, właściwość, indekser lub zdarzenie w klasie bazowej oznaczonej jako virtual umożliwi nadpisanie z klasy pochodnej.

Domyślnie, Członkowie klasy nie są wirtualnymi i nie mogą być tak oznaczone, jeśli modyfikatory statyczne, abstrakcyjne, prywatne lub nadpisujące.

Przykład Rozważmy metodę ToString() w systemie .Obiekt . Ponieważ ta metoda jest członkiem systemu.Obiekt jest dziedziczony we wszystkich klasach i dostarczy metody ToString() do wszystkich z nich.

namespace VirtualMembersArticle
{
    public class Company
    {
        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Company company = new Company() { Name = "Microsoft" };
            Console.WriteLine($"{company.ToString()}");
            Console.ReadLine();
        }   
    }
}

Wyjście poprzedniego kodu to:

VirtualMembersArticle.Company

Rozważmy, że chcemy zmienić standardowe zachowanie metod ToString () odziedziczonych po systemie.Obiekt w naszej klasie firmowej. Aby osiągnąć ten cel wystarczy użyć słowa kluczowego override, aby zadeklarować kolejną implementację tej metody.

public class Company
{
    ...
    public override string ToString()
    {
        return $"Name: {this.Name}";
    }         
}

Teraz, gdy wywołana jest metoda wirtualna, run-time sprawdzi, czy w swojej klasie pochodnej nie ma nadrzędnego członka i wywoła go, jeśli jest obecny. Wyjście naszej aplikacji będzie wtedy:

Name: Microsoft
W rzeczywistości, jeśli sprawdzisz System.Klasa obiektu okaże się, że metoda jest oznaczona jako wirtualna.
namespace System
{
    [NullableContextAttribute(2)]
    public class Object
    {
        ....
        public virtual string? ToString();
        ....
    }
}
 0
Author: Ivan Porta,
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-03-02 17:04:26