Estou tentando preencher um GridView
Entity Frameworkm usando, mas sempre que recebo o seguinte erro:
"O acessador de propriedade 'LoanProduct' no objeto 'COSIS_DAL.MemberLoan' lançou a seguinte exceção: A instância ObjectContext foi descartada e não pode mais ser usada para operações que requerem uma conexão."
Meu código é:
public List<MemberLoan> GetAllMembersForLoan(string keyword)
{
using (CosisEntities db = new CosisEntities())
{
IQueryable<MemberLoan> query = db.MemberLoans.OrderByDescending(m => m.LoanDate);
if (!string.IsNullOrEmpty(keyword))
{
keyword = keyword.ToLower();
query = query.Where(m =>
m.LoanProviderCode.Contains(keyword)
|| m.MemNo.Contains(keyword)
|| (!string.IsNullOrEmpty(m.LoanProduct.LoanProductName) && m.LoanProduct.LoanProductName.ToLower().Contains(keyword))
|| m.Membership.MemName.Contains(keyword)
|| m.GeneralMasterInformation.Description.Contains(keyword)
);
}
return query.ToList();
}
}
protected void btnSearch_Click(object sender, ImageClickEventArgs e)
{
string keyword = txtKeyword.Text.ToLower();
LoanController c = new LoanController();
List<COSIS_DAL.MemberLoan> list = new List<COSIS_DAL.MemberLoan>();
list = c.GetAllMembersForLoan(keyword);
if (list.Count <= 0)
{
lblMsg.Text = "No Records Found";
GridView1.DataSourceID = null;
GridView1.DataSource = null;
GridView1.DataBind();
}
else
{
lblMsg.Text = "";
GridView1.DataSourceID = null;
GridView1.DataSource = list;
GridView1.DataBind();
}
}
O erro está mencionando a LoanProductName
coluna do Gridview
. Mencionado: estou usando C #, ASP.net, SQL-Server 2008 como banco de dados de back-end.
Eu sou bastante novo no Entity Framework. Não consigo entender por que estou recebendo esse erro. Alguém pode me ajudar por favor?
c#
asp.net
entity-framework
barsan
fonte
fonte
query.Include("SomeOtherTable")
db.MemberLoans.Include("LoanProduct").OrderByDescending()
verificar a sintaxe, pois não tenho o VS na minha frente.db.MemberLoans.Include("LoanProduct").Include("SomeOtherTable)
. Verifique as respostas de @Tragedian e @lazyberezovskyRespostas:
Por padrão, o Entity Framework usa carregamento lento para propriedades de navegação. É por isso que essas propriedades devem ser marcadas como virtuais - o EF cria uma classe de proxy para sua entidade e substitui as propriedades de navegação para permitir o carregamento lento. Por exemplo, se você possui esta entidade:
O Entity Framework retornará o proxy herdado dessa entidade e fornecerá a instância DbContext a esse proxy para permitir o carregamento lento da associação posteriormente:
Portanto, a entidade possui uma instância do DbContext que foi usada para carregar a entidade. Esse é o seu problema. Você
using
bloqueou o uso do CosisEntities. Que descarta o contexto antes que as entidades sejam retornadas. Quando algum código tenta posteriormente usar a propriedade de navegação com carregamento lento, ele falha, porque o contexto é descartado naquele momento.Para corrigir esse comportamento, você pode usar o carregamento rápido das propriedades de navegação, necessárias mais tarde:
Isso pré-carregará todas as associações e o carregamento lento não será usado. Para obter detalhes, consulte o artigo Carregando entidades relacionadas no MSDN.
fonte
db.MemberLoans.Include(m => m.Membership).Include(m => m.LoanProduct).OrderByDescending(m => m.LoanDate);
isso gerará a consulta JOIN e retornará todos os dados de uma só vez.A
CosisEntities
turma é suaDbContext
. Ao criar um contexto em umusing
bloco, você define os limites para sua operação orientada a dados.No seu código, você está tentando emitir o resultado de uma consulta de um método e finalizar o contexto dentro do método. A operação para a qual você passa o resultado tenta acessar as entidades para preencher a visualização em grade. Em algum lugar do processo de ligação à grade, uma propriedade de carregamento lento está sendo acessada e o Entity Framework está tentando executar uma pesquisa para obter os valores. Falha, porque o contexto associado já terminou.
Você tem dois problemas:
Você é uma entidade de carregamento lento quando liga à grade. Isso significa que você está executando muitas operações de consulta separadas no SQL Server, o que atrasará tudo. Você pode corrigir esse problema, tornando as propriedades relacionadas prontamente carregadas por padrão ou solicitando que o Entity Framework as inclua nos resultados dessa consulta usando o
Include
método de extensãoVocê está encerrando seu contexto prematuramente: a
DbContext
deve estar disponível em toda a unidade de trabalho que está sendo executada, descartando-a somente quando você terminar o trabalho em mãos. No caso do ASP.NET, uma unidade de trabalho normalmente é a solicitação HTTP sendo manipulada.fonte
Bottom Line
Seu código recuperou dados (entidades) por meio de estrutura de entidade com carregamento lento ativado e depois que o DbContext foi descartado, seu código está fazendo referência a propriedades (entidades relacionadas / de relacionamento / entidades de navegação) que não foram solicitadas explicitamente.
Mais especificamente
O
InvalidOperationException
com esta mensagem sempre significa a mesma coisa: você está solicitando dados (entidades) de entidade-quadro após a DbContext foi descartado.Um caso simples:
(essas classes serão usadas para todos os exemplos nesta resposta e assumirão que todas as propriedades de navegação foram configuradas corretamente e têm tabelas associadas no banco de dados)
A última linha lançará o
InvalidOperationException
porque o dbContext não desativou o carregamento lento e o código está acessando a propriedade de navegação Pet após o contexto ser descartado pela instrução using.Depuração
Como você encontra a fonte dessa exceção? Além de observar a exceção em si, que será lançada exatamente no local em que ocorre, as regras gerais de depuração no Visual Studio se aplicam: coloque pontos de interrupção estratégicos e inspecione suas variáveis , passando o mouse sobre seus nomes, abrindo um ( Rápido) Observe a janela ou use os vários painéis de depuração, como Locals e Autos.
Se você deseja descobrir onde a referência está ou não está definida, clique com o botão direito do mouse no nome e selecione "Localizar todas as referências". Você pode colocar um ponto de interrupção em qualquer local que solicite dados e executar seu programa com o depurador conectado. Sempre que o depurador interrompe esse ponto de interrupção, é necessário determinar se sua propriedade de navegação deveria ter sido preenchida ou se os dados solicitados são necessários.
Maneiras de evitar
Desativar carregamento lento
Prós: em vez de lançar InvalidOperationException, a propriedade será nula. Acessar propriedades null ou tentar alterar as propriedades dessa propriedade lançará uma NullReferenceException .
Como solicitar explicitamente o objeto quando necessário:
No exemplo anterior, o Entity Framework materializará o animal de estimação além da pessoa. Isso pode ser vantajoso porque é uma chamada única para o banco de dados. (No entanto, também pode haver enormes problemas de desempenho, dependendo do número de resultados retornados e do número de propriedades de navegação solicitadas, nesse caso, não haverá penalidade no desempenho, pois ambas as instâncias são apenas um registro e uma associação única).
ou
No exemplo anterior, o Entity Framework materializará o Pet independentemente da Pessoa, fazendo uma chamada adicional ao banco de dados. Por padrão, o Entity Framework rastreia os objetos recuperados do banco de dados e, se encontrar propriedades de navegação correspondentes, preencherá automaticamente essas entidades. Nesse caso, porque
PetId
on doPerson
objeto corresponde aoPet.Id
, o Entity Framework atribui oPerson.Pet
aoPet
valor recuperado, antes que o valor seja atribuído à variável pet.Eu sempre recomendo essa abordagem, pois força os programadores a entender quando e como o código solicita dados via Entity Framework. Quando o código lança uma exceção de referência nula na propriedade de uma entidade, quase sempre você pode ter certeza de que não solicitou esses dados explicitamente.
fonte
É uma resposta muito tardia, mas resolvi o problema desativando o carregamento lento:
fonte
No meu caso, eu estava passando todos os modelos 'Users' para a coluna e não foram mapeados corretamente, então passei apenas 'Users.Name' e ele foi corrigido.
fonte
A maioria das outras respostas aponta para um carregamento ansioso, mas encontrei outra solução.
No meu caso, eu tinha um objeto EF
InventoryItem
com uma coleção deInvActivity
objetos filho.E como eu estava retirando da coleção de objetos filho em vez de uma consulta de contexto (com
IQueryable
), aInclude()
função não estava disponível para implementar o carregamento antecipado. Então, em vez disso, minha solução foi criar um contexto a partir do qual eu utilizeiGetLatestActivity()
eattach()
o objeto retornado:Portanto, você não está preso a um carregamento ansioso.
fonte
Se você estiver usando o ASP.NET Core e se perguntar por que recebeu essa mensagem em um dos métodos de controlador assíncrono, retorne um
Task
poucovoid
- o ASP.NET Core descarta os contextos injetados.(Estou postando esta resposta, pois essa pergunta é alta nos resultados da pesquisa para essa mensagem de exceção e é um problema sutil - talvez seja útil para as pessoas que pesquisam no Google.)
fonte