Relationship Problems Entity Framework Core 3,

Asked

Viewed 39 times

1

I’ll expose the code first, then explain the problem.

Pupil.Cs

using System.Collections.Generic;

namespace SalaDeAula.Models
{
    public class Aluno
    {
        public int AlunoId { get; set; }
        public string Nome { get; set; }
        public string Email { get; set; }
        public Turma Turma { get; set; }
        public List<Nota> Notas { get; set; }
    }
}

Disciplina.Cs

using System.Collections.Generic;

namespace SalaDeAula.Models
{
    public class Disciplina 
    {
        public int DisciplinaId { get; set; }
        public string nome { get; set; }
        public string descricao { get; set; }
        public Grade Grade { get; set; }
        public List<Nota> Nota { get; set; }
    }
}

Grade.Cs

using System.Collections.Generic;

namespace SalaDeAula.Models
{
    public class Grade
    {
        public int GradeId { get; set; }
        public string Descricao { get; set; }
        public List<Disciplina> Disciplinas { get; set; }
        public List<Turma> Turma { get; set; }
    }
}

Notes.Cs

using System.ComponentModel.DataAnnotations.Schema;

namespace SalaDeAula.Models
{
    public class Nota
    {
        public int NotaId { get; set; }
        public string Descricao { get; set; }
        public float nota { get; set; }

        [ForeignKey("AlunoId")]
        [InverseProperty("Notas")]
        public Aluno Aluno { get; set; }
        public Disciplina Disciplina { get; set; }
    }
}

Class.Cs

namespace SalaDeAula.Models
{
    public class Turma
    {
        public int TurmaId { get; set; }
        public string Serie { get; set; }
        public Grade Grade { get; set; }

    }
}

Context.Cs

using Microsoft.EntityFrameworkCore;

namespace SalaDeAula.Models
{
    public class Contexto : DbContext
    {
        public DbSet<Disciplina> Disciplinas { get; set; }
        public DbSet<Grade> Grades { get; set; }
        public DbSet<Turma> Turmas { get; set; }
        public DbSet<Aluno> Alunos { get; set; }
        public DbSet<Nota> Notas { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseSqlServer(@"Server=localhost;Database=EFcore.Escola;User Id=sa;Password=MyPassWord");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            #region Disciplina
                modelBuilder.Entity<Disciplina>().HasKey(p => p.DisciplinaId);
            #endregion
            #region Grade
                modelBuilder.Entity<Grade>().HasKey(p => p.GradeId);
                modelBuilder.Entity<Grade>().HasMany(p => p.Disciplinas);
            #endregion

            #region Turma
                modelBuilder.Entity<Turma>().HasKey(p => p.TurmaId);
                modelBuilder.Entity<Turma>().HasOne(p => p.Grade);
            #endregion

            #region Aluno
                modelBuilder.Entity<Aluno>().HasKey(p => p.AlunoId);
                modelBuilder.Entity<Aluno>().HasOne(p => p.Turma);
            #endregion
        
            #region Nota
                modelBuilder.Entity<Nota>().HasKey(p => p.NotaId);
                modelBuilder.Entity<Nota>().HasOne(p => p.Aluno);
                modelBuilder.Entity<Nota>()
                    .HasOne(p => p.Disciplina)
                    .WithMany(p => p.Nota)
                    .OnDelete(DeleteBehavior.SetNull);

            #endregion
        }
    }
}

Program.Cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using SalaDeAula.Models;

namespace SalaDeAula
{
    class Program
    {
        static void Main(string[] args)
        {
            using(var db = new Contexto())
            {
                db.Database.EnsureCreated();
                /*db.Disciplinas.Add(new Disciplina
                    {nome="Matemática", descricao="Matéria dos números."}
                );
                db.Disciplinas.Add(new Disciplina
                    {nome="Portuguẽs", descricao="Matéria das letras."}
                );
                db.Disciplinas.Add(new Disciplina
                    {nome="Geografia", descricao="Matéria dos paises."}
                );
                db.SaveChanges();

                List<Disciplina> disciplinas = new List<Disciplina>();
                foreach(var d in db.Disciplinas){
                    disciplinas.Add(d);
                }

                db.Grades.Add(new Grade{
                    Descricao="Matérias do 3º ano",
                    Disciplinas=disciplinas
                });
                db.SaveChanges();

                List<Grade> grades = new List<Grade>();
                foreach(var d in db.Grades){
                    grades.Add(d);
                }

                db.Turmas.Add(new Turma {
                    Grade=grades[0],
                    Serie="3-A",
                });

                db.SaveChanges();

                db.Alunos.Add(new Aluno {
                    Email="[email protected]",
                    Nome="Afonso Medeiros",
                    Turma=db.Turmas.First()
                });
                db.SaveChanges();*/
                

                db.Notas.Add(new Nota {
                    Aluno=db.Alunos.Single(a=>a.AlunoId==1),
                    Descricao="prova de matemática",
                    Disciplina=db.Disciplinas.Single(d=>d.DisciplinaId==1),
                    nota= 9.6F
                });
                db.Notas.Add(new Nota {
                    Aluno=db.Alunos.Single(a=>a.AlunoId==1),
                    Descricao="prova de Portuques",
                    Disciplina=db.Disciplinas.Single(d=>d.DisciplinaId==2),
                    nota= 6.2F
                });
                db.Notas.Add(new Nota {
                    Aluno=db.Alunos.Single(a=>a.AlunoId==1),
                    Descricao="prova de Geografia",
                    Disciplina=db.Disciplinas.Single(d=>d.DisciplinaId==3),
                    nota= 7.0F
                });
                db.SaveChanges();

                foreach (var i in db.Notas.ToList())
                {
                    Console.WriteLine($"Aluno {i.Aluno.Nome} | Turma {i.Aluno.Turma.Serie} | Disciplina: {i.Disciplina} | Nota {i.nota}");
                }
            }
        }
    }
}

Shell:

dotnet ef migrations "inicial"
dotnet ef database update
dotnet build
dotnet run

Error:

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at SalaDeAula.Program.Main(String[] args) in home/afonso/Documentos/projetos/C#/BrincandoEF/SalaDeAula/Program.cs:line 80

Well... the code part of the Program.Cs file that is commented on works and is consulted and is wonderful, but the uncommented part also "works" but in the Note class after I try to query after performing the saveChanges it returns "Student" as null... Someone would know how to fix it, I tried to follow both the doc of EF Core, but maybe I missed something.

  • In the database the notes are with the student id, right?

  • Yes, yes, they are!!

1 answer

1


To avoid unnecessary slower queries, despite the properties found in other tables in your model, the Entity Framework will not automatically bring their values.

To solve this your specific case, methods can be used Include and ThenInclude:

var notas = db.Notas
  .Include(notas => notas.Aluno)
    .ThenInclude(aluno => aluno.Turma)
  .ToList();

foreach (var i in notas)
{
  Console.WriteLine($"Aluno {i.Aluno.Nome} | Turma {i.Aluno.Turma.Serie} | Disciplina: {i.Disciplina} | Nota {i.nota}");
}

There are 3 different ways to work with the Entity Framework:

  • Eager loading: data is loaded in the initial query.
  • Lazy loading: data is loaded when necessary.
  • Explicit loading: data will be explicitly loaded later.

1. Eager loading

When you know exactly all the data that will be needed, you can use the Eager loading, as previously presented in this response (with the use of Include).

2. Lazy loading

In some situations it may be practical to use the Lazy loading. In this case it is recommended to use the package Microsoft.EntityFrameworkCore.Proxies. In addition, it will be necessary to ensure that the properties intended to be used the Lazy loading are virtual and change the configuration of your DB Context.

public class Nota
{
  (...)
  public virtual Aluno Aluno { get; set; }
}

public class Aluno
{
  (...)
  public virtual Turma Turma { get; set; }
}

// setup do db context
.AddDbContext<MyDbContext>(b =>
  b.UseLazyLoadingProxies()
   .UseSqlServer(myConnectionString));

3. Explicit loading

To use the Explicit loading it is necessary to load the data when intending to make use of them using the method Load.

var notas = db.Notas;
(...)
db.Entry(notas)
  .Collection(nota => nota.Aluno)
  .Load();
  • Thanks, it worked, but I still had two questions, the first: What is the Virtual modifier? in what exactly does it transform the attribute? and in trying to solve my problem I tried using Dataannotations, is it good to use data Annotations or should I use the configuration in the same context? or is it a matter of comfort?

Browser other questions tagged

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