Conflict between similar objects in the Entity Framework

Asked

Viewed 79 times

0

I have the following class:

public class Conteudo
{
    public long Id { get; set; }
    public string Categoria { get; set; }
    public string SubCategoria { get; set; }
    public string Descricao { get; set; }

    public string Status { get; set; }
    public string Obs { get; set; }
    public string Evidencias { get; set; }
    public string NSerie { get; set; }

    [ForeignKey("UsuarioAbertura")]
    public long? UsuarioAberturaId { get; set; }
    public virtual Usuario UsuarioAbertura { get; set; }

    [ForeignKey("UsuarioFechamento")]
    public long? UsuarioFechamentoId { get; set; }
    public virtual Usuario UsuarioFechamento { get; set; }

    public DateTime? DataHoraAbertura { get; set; }
    public DateTime? DataHoraFechamento { get; set; }


    public long ManifestacaoId { get; set; }
    [ForeignKey("ManifestacaoId")]
    public virtual Manifestacao Manifestacao { get; set; }
}

There are two types of User: User Closing and User Opening. One makes the opening of the Content and the other makes the closing.

The problem is that if the closing user is different from the one who opened the Content, when trying to read the database, the following error is shown:

System.ObjectDisposedException: 'The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.'

When it is the same User who makes the opening and closing no error is presented.

User class:

public class Usuario
{
    public long Id { get; set; }
    public string Apelido { get; set; }
    public string Nome { get; set; }
    public string Categoria { get; set; }
    public string Senha { get; set; }
    public string Status { get; set; }

    public virtual ICollection<Conteudo> ConteudosAbertura { get; set; }

    public virtual ICollection<Conteudo> ConteudosFechamento { get; set; }
}

Context class:

public class EFContext : DbContext
{
    public EFContext() : base("Pos_Venda_SAC")
    {
        //this.Configuration.LazyLoadingEnabled = false;
        Database.SetInitializer<EFContext>(
        new DropCreateDatabaseIfModelChanges<EFContext>()
        );
    }
    public DbSet<Cliente> Clientes { get; set; }
    public DbSet<Conteudo> Conteudos { get; set; }
    public DbSet<Manifestacao> Manifestacoes { get; set; }
    public DbSet<Usuario> Usuarios { get; set; }
    public DbSet<Destinatario> Destinatarios { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Usuario>()
            .HasMany<Conteudo>(c => c.ConteudosAbertura)
            .WithOptional(c => c.UsuarioAbertura)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Usuario>()
            .HasMany<Conteudo>(c => c.ConteudosFechamento)
            .WithOptional(c => c.UsuarioFechamento)
            .WillCascadeOnDelete(false);

    }
}

ADDED:

Code that generates the error:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.OleDb;
using PosVendaSAC.POCO;
using PosVendaSAC.Classes;
using PosVendaSAC.Contexts;

namespace PosVendaSAC
{
    public partial class FrmDetalhesConteudo : Form
    {
        DAL_Conteudos dalConteudos = new DAL_Conteudos();
        DAL_Usuario dalUsuario = new DAL_Usuario();
        Conteudo conteudoAtual = new Conteudo();
        private string nomeUsuario;

        private bool textoEmailAlterado;
        private bool textoTelefoneAlterado;
        private bool textoRamalAlterado;
        private bool textoCelularAlterado;
        private bool textoContatoAlterado;

        public FrmDetalhesConteudo(long idRow)
        {
            InitializeComponent();
            nomeUsuario = UsuarioLogado.Nome;
            conteudoAtual = dalConteudos.GetConteudoByID(idRow);
            PreencheCampos(conteudoAtual);
            DesabilitarEdicaoCampos();
            VerificarStatusFinalizado();
            textoEmailAlterado = false;
            textoTelefoneAlterado = false;
            textoRamalAlterado = false;
            textoCelularAlterado = false;
            textoContatoAlterado = false;
        }

        private void PreencheCampos(Conteudo conteudo)
        {
            txtEmpresaCliente.Text = conteudo.Manifestacao.Cliente.Empresa;
            txtContatoCliente.Text = conteudo.Manifestacao.Cliente.Contato;
            txtEmailCliente.Text = conteudo.Manifestacao.Cliente.Email;
            mskTelefoneCliente.Text = conteudo.Manifestacao.Cliente.Telefone;
            txtRamalCliente.Text = conteudo.Manifestacao.Cliente.Ramal;
            mskCelularCliente.Text = conteudo.Manifestacao.Cliente.Celular;
            txtCategoria.Text = conteudo.Categoria;
            txtSubCategoria.Text = conteudo.SubCategoria;
            txtConteudo.Text = conteudo.Descricao;
            txtStatus.Text = conteudo.Status;
            txtObs.Text = conteudo.Obs;
            txtEvidencias.Text = conteudo.Evidencias;
            lblTimeAbertura.Text = conteudo.DataHoraAbertura.ToString();
            lblTimeFechamento.Text = conteudo.DataHoraFechamento.ToString();
            lblUsuAbertura.Text = conteudo.UsuarioAbertura.Nome.ToString();
            txtNChamado.Text = conteudo.Manifestacao.NumeroChamado;
            txtNSerie.Text = conteudo.NSerie;
        }

        private void VerificarStatusFinalizado()
        {
            if (txtStatus.Text == "Finalizado")
            {
                if (!UsuarioLogado.IsEng())
                {
                    cboNovoStatus.Enabled = false;
                    cboNovoStatus.Text = "Status finalizado não pode ser alterado";
                }
                lblTimeFechamento.Visible = true;
                lblTitFechamento.Visible = true;
                lblTitIntervalo.Visible = true;
                lblDiasIntervalo.Visible = true;
                lblTitUsuFechamento.Visible = true;
                lblUsuFechamento.Text = conteudoAtual.UsuarioFechamento.Nome;
                lblUsuFechamento.Visible = true;
                CalculaIntervalo();
            }
        }

        private void DesabilitarEdicaoCampos()
        {
            foreach (Control ctrl in gbxConteudo.Controls)
            {
                if (ctrl is TextBox)
                {
                    ((TextBox)ctrl).ReadOnly = true;
                }
            }

            txtNSerie.ReadOnly = false;
            txtEmpresaCliente.ReadOnly = true;
            txtStatus.ReadOnly = true;
        }

        private void cmdSalvar_Click(object sender, EventArgs e)
        {
            //VerificaAlteracaoDadosContato();
            VerificaAlteracaoStatus();
            System.Threading.Thread.Sleep(200);
            this.Close();
        }

        private void VerificaAlteracaoStatus()
        {
            if (cboNovoStatus.Text == "Finalizado")
            {
                DialogResult dialogResult = MessageBox.Show("Confirma a alteração do status para 'Finalizado'? Após finalizado um registro não pode mais ser alterado.", "Importante!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (dialogResult == DialogResult.Yes)
                {
                    UpdateConteudo();
                    System.Threading.Thread.Sleep(200);
                    VerificarStatusFinalizado();
                    NotificaTermino();
                    MessageBox.Show("Registro atualizado com sucesso.");
                }
                else
                {
                    return;
                }
            }
            else
            {
                UpdateConteudo();
            }
        }

        private void UpdateConteudo()
        {
            using (var context = new EFContext())
            {
                var newConteudo = context.Conteudos.Find(conteudoAtual.Id);
                if (cboNovoStatus.Text == "Finalizado")
                {
                    newConteudo.DataHoraFechamento = PegaDataHoraUsuario.DataHoraPadrao();
                    newConteudo.UsuarioFechamentoId = UsuarioLogado.Id;
                }
                if (cboNovoStatus.SelectedIndex > -1)
                {
                    newConteudo.Status = cboNovoStatus.Text;
                }
                newConteudo.Obs = txtObs.Text;
                newConteudo.Evidencias = txtEvidencias.Text;
                newConteudo.NSerie = txtNSerie.Text;
                context.SaveChanges();
            }
        }

        private void UpdateDadosContato()
        {
            using (var context = new EFContext())
            {
                var newContato = context.Clientes.Find(conteudoAtual.Manifestacao.Cliente.Id);
                newContato.Email = txtEmailCliente.Text;
                newContato.Celular = mskCelularCliente.Text;
                newContato.Ramal = txtRamalCliente.Text;
                newContato.Telefone = mskTelefoneCliente.Text;
                newContato.Contato = txtContatoCliente.Text;
                context.SaveChanges();
            }
        }

        private void NotificaTermino()
        {
            string procedimento = "fechamento";
            string dataHora = PegaDataHoraUsuario.DataHoraInvertida();

            string corpoEmailString = "<p><strong><font size='4'>Manifestação Finalizada</font></p>";
            corpoEmailString += "<p>Chamado: " + txtNChamado.Text + "</p>";
            corpoEmailString += "<p><strong><font size='3'>Empresa: " + txtEmpresaCliente.Text + "</font></p>";
            corpoEmailString += "<p><font size='2'> Conteúdo " + ": </font> </p>";
            corpoEmailString += "<p>Categoria: " + txtCategoria.Text + "</p>";
            corpoEmailString += "<p>Subcategoria: " + txtSubCategoria.Text + "</p>";
            corpoEmailString += "<p>Conteúdo: " + txtConteudo.Text + "</p>";
            corpoEmailString += "<br/>";
            corpoEmailString += "<p>Contato: " + txtContatoCliente.Text + "</p>";
            corpoEmailString += "<p>e-mail: " + txtEmailCliente.Text + "</p>";
            corpoEmailString += "<p>Telefone: " + mskTelefoneCliente.Text + "</p>";
            corpoEmailString += "<p>Ramal: " + txtRamalCliente.Text + "</p>";
            corpoEmailString += "<p>Celular: " + mskCelularCliente.Text + "</p>";
            corpoEmailString += "<p>Conteúdo encerrado por: " + nomeUsuario + "</p>";
            corpoEmailString += "<p>Data e hora do encerramento: " + lblTimeFechamento.Text + "</p>";
            corpoEmailString += "<p>Aberto em: " + lblTimeAbertura.Text + " por: " + lblUsuAbertura.Text + "</p>";
            corpoEmailString += "<p>Tempo decorrido até o fechamento: " + lblDiasIntervalo.Text + "</p>";

            List<string> vazio = new List<string>() { "", "" };

            string resultado = SendMail.EnviaMensagemEmail(StringsProjeto.remetente, "Manifestação Finalizada", corpoEmailString, procedimento, vazio);
        }    

        private void CalculaIntervalo()
        {
            DateTime fechamento = Convert.ToDateTime(lblTimeFechamento.Text.ToString());
            DateTime abertura = Convert.ToDateTime(lblTimeAbertura.Text.ToString());
            TimeSpan ts1 = fechamento.Subtract(abertura);
            string intervaloDias = ts1.ToString("dd");
            string intervaloHoras = ts1.ToString("hh");
            lblDiasIntervalo.Text = intervaloDias + " dias e " + intervaloHoras + " horas ";

        }

        private void txtEmailCliente_TextChanged(object sender, EventArgs e)
        {
            textoEmailAlterado = true;
        }

        private void mskTelefoneCliente_MaskInputRejected(object sender, MaskInputRejectedEventArgs e)
        {
            textoTelefoneAlterado = true;
        }

        private void txtRamalCliente_TextChanged(object sender, EventArgs e)
        {
            textoRamalAlterado = true;
        }

        private void mskCelularCliente_MaskInputRejected(object sender, MaskInputRejectedEventArgs e)
        {
            textoCelularAlterado = true;
        }

        private void txtContatoCliente_TextChanged(object sender, EventArgs e)
        {
            textoContatoAlterado = true;
        }
    }
}
  • What code generates this error?

  • lblUsuFechanance.Text = contentAtual.UsuarioFechanication.Name;

  • Seeing only one line of code does me no good

  • @LINQ, added the code by editing the question (above).

1 answer

2


Come on, in spite of your DAL is masking the problem, I believe the method GetConteudoByID(id) is doing something similar.:

using (var context = new EFContext())
{
    return context.Conteudos.Find(id);
}

when doing this, the connection is being closed when the Dispose() of context is called, just as the EF context is destroyed.

now let’s look at the following line.:

conteudoAtual.UsuarioFechamento.Nome

As during the content query, you did not perform a EagerLoad, then it will be consulted only when it is accessed, making a LazyLoad, as the context has already been dropped, so the connection is no longer available...

What you can do in the short term, is change your method GetConteudoByID(id) in DAL for.:

using (var context = new EFContext())
{
    return context.Conteudos
        .Include(u => u.UsuarioAbertura)
        .Include(u => u.UsuarioFechamento)
        .Include(u => u.Manifestacao)
        .FirstOrDefault(u => u.Id == id);
}

In the long term, I advise you to abandon this approach with DAL, you’re just artificially limiting the EF, in the long run you will see that besides not bringing benefits, some problems will be introduced.

If you really want to repurpose GetConteudoByID(id), then make an extension for your EFContext, and do not be afraid to access the EFContext right on the form.

public static class DAL_Conteudos
{
    public static Conteudo GetConteudoByID(this EFContext context, int id)
    {
        return context.Conteudos
            .Include(u => u.UsuarioAbertura)
            .Include(u => u.UsuarioFechamento)
            .Include(u => u.Manifestacao)
            .FirstOrDefault(u => u.Id == id);
    }
}

believe me, it’s not bad to do.:

public partial class FrmDetalhesConteudo : Form
{        
    EFContext context = new EFContext();
    Conteudo conteudoAtual = new Conteudo();

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            context?.Dispose();
        }
        base.Dispose(disposing);
    }

    public FrmDetalhesConteudo(long idRow)
    {
        InitializeComponent();
        nomeUsuario = UsuarioLogado.Nome;
        conteudoAtual = context.GetConteudoByID(idRow);
        PreencheCampos(conteudoAtual);
        DesabilitarEdicaoCampos();
        VerificarStatusFinalizado();
        textoEmailAlterado = false;
        textoTelefoneAlterado = false;
        textoRamalAlterado = false;
        textoCelularAlterado = false;
        textoContatoAlterado = false;
    }

    private void VerificarStatusFinalizado()
    {
        if (txtStatus.Text == "Finalizado")
        {
            if (!UsuarioLogado.IsEng())
            {
                cboNovoStatus.Enabled = false;
                cboNovoStatus.Text = "Status finalizado não pode ser alterado";
            }
            lblTimeFechamento.Visible = true;
            lblTitFechamento.Visible = true;
            lblTitIntervalo.Visible = true;
            lblDiasIntervalo.Visible = true;
            lblTitUsuFechamento.Visible = true;
            lblUsuFechamento.Text = conteudoAtual.UsuarioFechamento.Nome;
            lblUsuFechamento.Visible = true;
            CalculaIntervalo();
        }
    }
}

If you want to know more about Por que não é legal usar DAL/Repository com EF.:

When to use Entity Framework with Repository Pattern?

  • Thank you very much!!!

Browser other questions tagged

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