Suppose Model of Product :
public class Produto
{
[Key]
public Guid ProdutoId { get; set; }
public Guid CategoriaId { get; set; }
public Guid FabricanteId { get; set; }
[Required]
public String Descricao { get; set; }
[Required]
public Decimal Preco { get; set; }
public virtual Categoria Categoria { get; set; }
public virtual Fabricante Fabricante { get; set; }
}
Notice that Produto
has two relationships: Categoria
and Fabricante
. Usually the Entity Framework is already configured to bring in all the data alone when requested by the code. This is an implementation that uses lazy load . In this implementation, selecting Produto
, Categoria
and Fabricante
receive temporary objects (Dynamic Proxies). These objects, when asked to provide the value of some property (for example, the name of a Categoria
), are replaced by the objects of the Model itself. In this process, selections or local cache searches occur, depending on the situation.
Basic Selections
The sentence below:
var produtos = context.Produtos.ToList();
is the equivalent of doing:
select * from Produtos
context
is a variable that represents the context of your application, this class object derived from DbContext
.
Selecting Dependent Entities
To bring in the manufacturers and categories of each product, the idea is to use the following command:
var produtos = context.Produtos
.Include(p => p.Fabricante)
.Include(p => p.Categoria)
.ToList();
Which is equivalent to:
select * from Produtos
inner join Fabricantes on Fabricantes.FabricanteId = Produtos.FabricanteId
inner join Categorias on Categorias.CategoriaId = Produto.CategoriaId
The Include()
statement, as opposed to the lazy load, forces the Entity Framework to fetch the data immediately. That is, a SQL is generated with the joins specified above.
To put conditions on your selection, use Where()
:
var produtos = context.Produtos
.Include(p => p.Fabricante)
.Include(p => p.Categoria)
.Where(p => p.Categoria.Nome == "Calçados")
.ToList();
For compound conditions, just use logical operators, such as &&
or ||
:
var produtos = context.Produtos
.Include(p => p.Fabricante)
.Include(p => p.Categoria)
.Where(p => p.Categoria.Nome == "Calçados" && p.Fabricante.Nome != "Adidas")
.ToList();
Cardinality N
Suppose now that Fabricante
is implemented as follows:
public class Fabricante
{
[Key]
public Guid FabricanteId { get; set; }
[Required]
public String Nome { get; set; }
public virtual ICollection<Produto> Produtos { get; set; }
}
Just as Produto
belongs to Fabricante
, Fabricante
has several Produtos
. The ICollection
above specifies this relationship.
To select a Fabricante
and its Produtos
, use the following sentence:
var fabricantes = context.Fabricantes.Include(f => f.Produtos).ToList();
Persisting Data
To insert a new Produto
, the following sequence of steps does this work:
var produto = new Produto
{
ProdutoId = Guid.NewGuid(),
Nome = "Tênis de Corrida",
Preco = 200,
Fabricante = context.Fabricantes.SingleOrDefault(f => f.Nome == "Adidas"),
Categoria = context.Categorias.SingleOrDefault(c => c.Nome == "Calçados")
};
context.Produtos.Add(produto);
context.SaveChanges();
Notice that Ids are not inserted directly. Instead, objects that have all the information that the Entity Framework needs to perform the insertion are populated.
Similarly, an update is done as follows:
var produto = context.Produtos.SingleOrDefault(p => p.Nome == "Tênis de Corrida");
produto.Preco = 250;
context.Entry(produto).State = EntityState.Modified;
context.SaveChanges();