Entity Relationship Framework 1:N

Asked

Viewed 679 times

2

Hello.

I have the following classes...

Sales class:

[Table("venda")]
public class Vendas
{        
    public Vendas()
    {
        ItensVendas= new List<ItensVendas>();

    }
    [Key]
    public int Id { get; set; }
    public string NOME_VENDA { get; set; }
    public DateTime? DATA { get; set; }
    public int ID_CLIENTE { get; set; }

    public virtual IEnumerable<ItensVendas> ItensVendas{ get; set; }

}

Itenssales class:

[Table("ITENS_VENDA")]
public class ItensVendas
{
    [Key]
    public int Id { get; set; }
    public int ID_RPODUTO { get; set; }
    public int QTD { get; set; }
    public decimal VALOR { get; set; }

    [ForeignKey("venda")]
    public int VendaId { get; set; }

    public virtual Vendas venda { get; set; }

}

Controller:

     public class VendasController : ApiController
        {
            private Contexto ctx = new Contexto();

            [HttpGet]
            public  IEnumerable<Vendas> GetVendas()
            {



                using (Contexto vendaCtx = new Contexto()) {
                    return vendaCtx.Vendas.ToList();

              } 
            }
}

Context:

public class Contexto : DbContext
{
    public Contexto() : base("conn")
    { 
       this.Configuration.LazyLoadingEnabled = true;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Vendas> Vendas { get; set; }
    public DbSet<ItensVendas> ItensVendas { get; set; }
}

In the Getsales controller method, Eleme returns a JSON containing the sale data, but the sale items come empty as below.

[{"Id":1,"NOME_VENDA":"VENDA 1","DATA":"2017-11-15T20:08:52","ID_CLIENTE":1,"ITENSVENDAS":[]}]

I’d like to bring the items from this sale too, how could I do that?

Thank you!

3 answers

4

You can do according to the example below using the "Include":

vendaCtx.Vendas 
  .Include(b => b.ItensVendas).ToList(); 

3

Probably its configuration is Lazyloading = False; If you want to take a look at how it works, click here

In that regard, you have two options:

1- Lets Lazy loading = true

2- Dar include what you need to bring. Example:

using (Contexto vendaCtx = new Contexto()) 
{
   return vendaCtx.Vendas.Include(b => b.ItensVendas).ToList();
} 

in the classes, its associations in the bank must contain the property virtual and use ICollection instead of IEnumerable (lazyloading standard). You should therefore change your sales class as follows:

[Table("venda")]
public class Vendas
{        
    public Vendas()
    {
        ItensVendas= new List<ItensVendas>();

    }
    [Key]
    public int Id { get; set; }
    public string NOME_VENDA { get; set; }
    public DateTime? DATA { get; set; }
    public int ID_CLIENTE { get; set; }

    public virtual ICollection<ItensVendas> ItensVendas{ get; set; }

}
  • I enabled Lazy loading, but started having the following error: The Entitytype Models.Sales does not declare a navigation Property with the name 'Itenssales'. And in class I have a Property with this name.

  • Beauty, but in your Configuration (where you map your entities to generate the bank), there is this relationship?

  • switch to public virtual Ienumerable<Itenssales> Itensvendas{ get; set; } (put the VIRTUAL) and test again, if it is mapped all right to generate the bank.

  • Even switching to public virtual Ienumerable<Itenssales> Itenssales{ get; set; } the error remains the same.

  • Then post (edit your question) how you configured the mapping of your classes for me to check if there are any errors?

  • @Core changed to Icollection tb, because when it comes from the bank, it understands as a collection

  • Same mistake. You talked about the mapping, would have to have a new class for that? I did the example of a video lesson , was done on top of an existing base.

  • you ta mapping with date Annotation?

  • Yes. The correct thing would be to use Fluent api?

  • I believe it is the best scenario. You will hardly have problems of this type configuring with the Fluent. If you need help with the mapping, you can find me.

Show 5 more comments

3

You can use a sub select to include the sale items.

public  IEnumerable<Vendas> GetVendas()
{
    using (Contexto ctx = new Contexto()) 
    {
        return ctx.Vendas
        .Select(x => new Vendas
        {
            Id = x.Id,
            NOME_VENDA = x.NOME_VENDA,
            DATA = x.DATA,
            ID_CLIENTE = x.ID_CLIENTE,
            ItensVendas = ctx.ItensVendas.Where(i => i.VendaId == x.Id)
        })
        .ToList();

    } 
}
  • Just remembering that in this case he will make 2 queries to the bank and, depending on the need, may have a lower performance than a single query that brings the relationship already (I did not say it is wrong, I’m only commenting on performance)

  • 1

    @Ayrtongiffoni, will not make two trips to the bank, because the query is only finalized after Tolist() ... or until then the query is being mounted by EF and only with Tolist() it will be launched to the bank.

  • When I said two queries, I meant subquery. In this case, with Join it can be more performative.

  • 1

    @Ayrtongiffoni, if you analyze the query that the EF mounted, will note that it does so behind.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.