What is the difference between using virtual property or not in EF?

20

I have my models

public class Cliente
{
   public int Id {get;set;}
   public string Nome {get;set;}
}

and

public class Pedido
{
   public int Id {get;set;}
   public int ClienteId {get;set;}
   public virtual Cliente Cliente {get;set;}
}

Following the example above, what is the difference between

public virtual Cliente Cliente {get;set;}

and

public Cliente Cliente {get;set;}

I always notice that when using virtual my Client model is loaded

for example:

var pedido = dbo.Pedidos.Find(1);

If I try to access pedido.Cliente it is not null when virtual is

What's the difference? How does EF do query ? Which way do I have the most performance?

    
asked by anonymous 04.03.2015 / 03:26

3 answers

27

Lazy Loading

  

Lazy Loading is the mechanism used by persistence frameworks   to load demand information. This mechanism   lighter entities, because their associations are loaded only in the   moment that the method that makes the associative data available is   called. So when objects are returned by a query, the   objects are not loaded at the same time, instead they   are loaded automatically when the navigation property is   accessed.

The virtual f modifier is used by EF to do Lazy Loading , which needs to create proxy instances that will be overridden in these virtual properties.

So you have the impression that this object is always loaded. But in fact he is not. A virtual property is only loaded via lazy loading at the time of the first reference to this property. At this point the EF performs a new query on the database requesting only the data below the object hierarchy of that property.

This can be noticed by debugging your code in Visual Studio, the virtual property will be loaded the moment you check its value.

Using Lazy Loading can indeed bring performance issues. In your example, if you make a query that returns, say, 100 Pedidos , without explicitly loading the (eager loading) clients, when referencing any information of Cliente , for each different client, query in the database. So in this case you could have 100 new queries to the database.

var pedidos = db.Pedidos.ToList(); // não traz nenhuma informação de cliente
foreach (var pedido in pedidos) 
{
    var nome = pedido.Cliente.Nome; // aqui é feita a carga por Lazy Loading
}

Eager Loading

To avoid this effect, you can tell that you want EF to Eager Loading from clients using a Include clause.

var pedidos = db.Pedidos.Include(m => m.Cliente).ToList(); // inclui cliente na query
foreach (var pedido in pedidos) 
{
    var nome = pedido.Cliente.Nome; // os dados de cliente já estão carregados
}

In this way the SQL query will include the clients in the query.

In cases where we do not use the virtual f modifier, we can only access Cliente for Eager Loading .

EF uses Lazy Loading by default in properties marked with the virtual f modifier, otherwise it is turned off and therefore the object reference is null (except when we use eager loading via Include ).

You can configure EF to not work with Lazy Loading even when we have virtual properties.

public class MeuContexto : DbContext 
{ 
    public MeuContexto () 
    { 
        this.Configuration.LazyLoadingEnabled = false; 
    } 
}
    
04.03.2015 / 19:21
13

I agree with the @bigown answer , and I have a few more points to add.

Although I do not actually work with EF , I know that it, like NHibernate (or similar to EF), creates a derived class called proxy in>, with the main purpose being the creation of triggers for the getters and setters in your entity, so the ORM can control, how, and if an attribute / property of its persistent entity has been changed, to be able to take the actions.

So if you do not leave a virtual attribute, you are explicitly saying that it can not be overridden in a class derived from yours, so ORM could not implement a proxy for this attribute / property, and therefore can not implement the triggers.

  

Note: with NHibernate it is mandatory to use the virtual modifier in all properties mapped to the ORM, if this does not occur an error is generated at the time of creating the configuration of the same. So he needs the creation of proxis for its use, since the EF, not explicitly needed from the virtual (hence, I no longer understand how it does, a possible explanation maybe is the comment from @TobyMosque ).

    
04.03.2015 / 13:23
11

It creates a class derived from its class to work internally. This is a pattern called dynamic proxy . This makes it easier to navigate the data.

Polymorphism

How the class is derived the call needs to be made in the get method of the derived class property that will have the effective data loading logic. Without the virtual there is no polymorphism and the method called is that of its Pedido class that contains no logic of therefore it is coherent to have null in this case.

The virtual is used just to create an indirection, so the method to be called is not called directly but through a table that will indicate which is the correct method to be called in the class hierarchy according to the concrete data being manipulated.

If you call a method that was not defined as virtual , the call is made directly and fixed, that is, if the method being called is the get Cliente of class Pedido , it is always it even though it will be called and there will be no way to call the get Cliente of a derived class even if the object is of the type of the derived class.

Conclusion

Execution of query will be the responsibility of get Cliente in the internal EF class derived from its Pedido class. The data load occurs on demand, called lazy loading , and without the virtual the load should be done manually, perhaps in its class Pedido in the immediate form eager loading . The query is mounted with some form of LINQ (see comment below TobyMosque).

The performance of each depends on how you will use it. In many cases the "lazy load" can save processing but in some access patterns this may turn against you.

    
04.03.2015 / 03:50