¿Por qué usar ‘virtual’ para las propiedades de clase en las definiciones del modelo de Entity Framework?

En el siguiente blog: http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

El blog contiene el siguiente ejemplo de código:

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 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; } } 

¿Cuál es el propósito de usar virtual al definir una propiedad en una clase? ¿Qué efecto tiene?

Permite a Entity Framework crear un proxy alrededor de la propiedad virtual para que la propiedad pueda admitir la carga diferida y un seguimiento de cambios más eficiente. Consulte ¿Qué efecto (s) puede tener la palabra clave virtual en Entity Framework 4.1 POCO Code First? para una discusión más completa.

Editar para aclarar “crear un proxy alrededor”: por “crear un proxy alrededor” me refiero específicamente a lo que hace el Entity Framework. Entity Framework requiere que sus propiedades de navegación se marquen como virtuales para que se admita la carga diferida y el seguimiento eficiente de cambios. Vea los Requisitos para Crear Proxies POCO .
Entity Framework usa herencia para admitir esta funcionalidad, por lo que requiere que ciertas propiedades se marquen como virtuales en sus POCO de clase base. Literalmente crea nuevos tipos que se derivan de sus tipos de POCO. Por lo tanto, su POCO actúa como un tipo base para las subclases creadas dinámicamente de Entity Framework. Eso es lo que quise decir con “crear un proxy alrededor”.

Las subclases creadas dinámicamente creadas por Entity Framework se vuelven aparentes cuando se usa Entity Framework en tiempo de ejecución, no en tiempo de comstackción estática. Y solo si habilita las funciones de carga lenta o cambio de seguimiento de Entity Framework. Si opta por no utilizar nunca las funciones de carga diferida o de seguimiento de cambios de Entity Framework (que no es el valor predeterminado), no necesita declarar ninguna de sus propiedades de navegación como virtuales. Entonces usted es responsable de cargar esas propiedades de navegación, ya sea utilizando lo que Entity Framework denomina “carga ansiosa”, o recuperando manualmente los tipos relacionados en múltiples consultas de bases de datos. Sin embargo, puede y debe usar funciones de carga lenta y de seguimiento de cambios para sus propiedades de navegación en muchos escenarios.

Si fuera a crear una clase independiente y marcar propiedades como virtuales, y simplemente construir y usar instancias de esas clases en su propia aplicación, completamente fuera del scope de Entity Framework, entonces sus propiedades virtuales no ganarían nada en su propio.

Editar para describir por qué las propiedades se marcarán como virtuales

Propiedades tales como:

  public ICollection RSVPs { get; set; } 

No son campos y no deberían considerarse como tales. Estos se denominan getters y setters y, en el momento de la comstackción, se convierten en métodos.

 //Internally the code looks more like this: public ICollection get_RSVPs() { return _RSVPs; } public void set_RSVPs(RSVP value) { _RSVPs = value; } private RSVP _RSVPs; 

Es por eso que están marcados como virtuales para su uso en Entity Framework, permite que las clases creadas dinámicamente anulen las funciones get y set generadas internamente. Si los get / setters de su propiedad de navegación funcionan para usted en el uso de su Entity Framework, intente revisarlos solo para propiedades, recomstackr y ver si Entity Framework puede funcionar aún correctamente:

  public virtual ICollection RSVPs; 

La palabra clave virtual en C # permite que un método o propiedad sea anulado por clases secundarias. Para obtener más información, consulte la documentación de MSDN sobre la palabra clave ‘virtual’.

ACTUALIZACIÓN: es evidente que mi respuesta no se ajusta a lo que se esperaba dadas las circunstancias de la pregunta, pero la dejo aquí para cualquiera que busque una respuesta simple a la pregunta original , no descriptiva.

Entiendo la frustración de OP, este uso de virtual no es para la abstracción de plantilla para la que el modificador virtual de facto es efectivo.

Si alguno todavía está luchando con esto, ofrecería mi punto de vista, mientras trato de mantener las soluciones simples y la jerga al mínimo:

Entity Framework en una pieza simple utiliza la carga diferida, que es el equivalente a preparar algo para su futura ejecución. Eso se ajusta al modificador ‘virtual’, pero hay más en esto.

En Entity Framework, el uso de una propiedad de navegación virtual le permite denotarlo como el equivalente de una clave externa con nulo en SQL. NO TIENE que unirse con entusiasmo a cada tabla con clave al realizar una consulta, pero cuando necesita la información, se vuelve impulsada por la demanda.

También mencioné que se puede anular porque muchas propiedades de navegación no son relevantes al principio. es decir, en un escenario de cliente / pedidos, no tiene que esperar hasta el momento en que se procesa un pedido para crear un cliente. Puede hacerlo, pero si tuvo un proceso de varias etapas para lograr esto, puede encontrar la necesidad de conservar los datos del cliente para su posterior finalización o para su implementación en futuros pedidos. Si se implementaran todas las propiedades de navegación, tendría que establecer cada clave externa y campo relacional en el guardado. Eso simplemente restablece los datos en la memoria, lo que frustra el rol de la persistencia.

Entonces, si bien puede parecer críptico en la ejecución real en tiempo de ejecución, he encontrado que la mejor regla general para usar sería: si está produciendo datos (leyendo en un Modelo de Vista o Modelo Serializable) y necesita valores antes de las referencias, no lo haga usar virtual; Si su scope está recostackndo datos que pueden estar incompletos o una necesidad de búsqueda y no requiere cada parámetro de búsqueda completado para una búsqueda, el código hará un buen uso de la referencia, similar al uso de propiedades de valor nullable int? ¿largo?. Además, abstraer su lógica de negocios de su colección de datos hasta que la necesidad de inyectarlo tenga muchos beneficios de rendimiento, similar a crear instancias de un objeto e iniciarlo en nulo. Entity Framework utiliza mucha reflexión y dinámica, lo que puede degradar el rendimiento, y la necesidad de contar con un modelo flexible que pueda escalar a la demanda es fundamental para la gestión del rendimiento.

Para mí, eso siempre tenía más sentido que usar jerga tecnológica sobrecargada como proxies, delegates, manejadores y demás. Una vez que llegue a su tercera o cuarta lengua de progtwigción, puede complicarse con esto.

Es bastante común definir propiedades de navegación en un modelo para ser virtual. Cuando una propiedad de navegación se define como virtual, puede aprovechar ciertas funcionalidades de Entity Framework. El más común es la carga lenta.

La carga diferida es una buena característica de muchos ORM porque le permite acceder dinámicamente a los datos relacionados desde un modelo. No buscará innecesariamente los datos relacionados hasta que realmente se acceda, reduciendo así la consulta inicial de datos de la base de datos.

Del libro “ASP.NET MVC 5 con Bootstrap y Knockout.js”

En el contexto de EF, marcar una propiedad como virtual permite a EF utilizar la carga diferida para cargarla. Para cargas perezosas para trabajar, EF tiene que crear un objeto proxy que anule sus propiedades virtuales con una implementación que carga la entidad referenciada cuando se accede por primera vez. Si no marca la propiedad como virtual, la carga diferida no funcionará.