Estoy tratando de llenar un GridView
Entity Frameworkm usando pero cada vez recibo el siguiente error:
"El descriptor de acceso de propiedad 'LoanProduct' en el objeto 'COSIS_DAL.MemberLoan' produjo la siguiente excepción: la instancia de ObjectContext se ha eliminado y ya no se puede usar para operaciones que requieren una conexión".
Mi código es:
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();
}
}
El error está mencionando la LoanProductName
columna de la Gridview
. Mencionado: estoy usando C #, ASP.net, SQL-Server 2008 como base de datos de back-end.
Soy bastante nuevo en Entity Framework. No puedo entender por qué recibo este error. ¿Alguien puede ayudarme por favor?
c#
asp.net
entity-framework
Barsan
fuente
fuente
query.Include("SomeOtherTable")
db.MemberLoans.Include("LoanProduct").OrderByDescending()
verificar la sintaxis porque no tengo VS frente a mí.db.MemberLoans.Include("LoanProduct").Include("SomeOtherTable)
. Compruebe las respuestas de @Tragedian y @lazyberezovskyRespuestas:
De forma predeterminada, Entity Framework usa lazy-loading para las propiedades de navegación. Es por eso que estas propiedades deben marcarse como virtuales: EF crea una clase proxy para su entidad y anula las propiedades de navegación para permitir la carga diferida. Por ejemplo, si tiene esta entidad:
Entity Framework devolverá el proxy heredado de esta entidad y proporcionará una instancia de DbContext a este proxy para permitir la carga diferida de la membresía más adelante:
Entonces, la entidad tiene una instancia de DbContext que se usó para cargar la entidad. Ese es tu problema. Tiene
using
bloqueado el uso de CosisEntities. Que dispone el contexto antes de que se devuelvan las entidades. Cuando algún código luego intenta usar la propiedad de navegación con carga lenta, falla, porque el contexto está dispuesto en ese momento.Para corregir este comportamiento, puede usar la carga ansiosa de las propiedades de navegación que necesitará más adelante:
Eso precargará todas las membresías y no se utilizará la carga diferida. Para obtener más detalles, consulte el artículo Carga de entidades relacionadas en MSDN.
fuente
db.MemberLoans.Include(m => m.Membership).Include(m => m.LoanProduct).OrderByDescending(m => m.LoanDate);
eso generará consultas JOIN y devolverá todos los datos a la vez.La
CosisEntities
clase es tuyaDbContext
. Cuando crea un contexto en unusing
bloque, está definiendo los límites para su operación orientada a datos.En su código, está tratando de emitir el resultado de una consulta de un método y luego finalizar el contexto dentro del método. La operación a la que le pasa el resultado intenta acceder a las entidades para completar la vista de cuadrícula. En algún lugar del proceso de vinculación a la cuadrícula, se accede a una propiedad con carga lenta y Entity Framework está intentando realizar una búsqueda para obtener los valores. Falla porque el contexto asociado ya ha finalizado.
Tienes dos problemas:
Son entidades de carga lenta cuando se unen a la cuadrícula. Esto significa que está realizando muchas operaciones de consulta por separado en SQL Server, que ralentizarán todo. Puede solucionar este problema haciendo que las propiedades relacionadas se carguen de manera predeterminada o solicitando a Entity Framework que las incluya en los resultados de esta consulta mediante el
Include
método de extensión.Está finalizando su contexto prematuramente: a
DbContext
debería estar disponible en toda la unidad de trabajo que se realiza, solo desechando cuando haya terminado con el trabajo en cuestión. En el caso de ASP.NET, una unidad de trabajo suele ser la solicitud HTTP que se maneja.fuente
Línea de fondo
Su código ha recuperado datos (entidades) a través del marco de entidad con la carga lenta habilitada y después de que se haya eliminado el DbContext, su código hace referencia a propiedades (entidades relacionadas / de relación / navegación) que no se solicitaron explícitamente.
Más específicamente
El
InvalidOperationException
con este mensaje siempre significa lo mismo: está solicitando datos (entidades) de entity-framework después de que se haya eliminado el DbContext.Un caso simple:
(estas clases se usarán para todos los ejemplos en esta respuesta, y suponen que todas las propiedades de navegación se han configurado correctamente y tienen tablas asociadas en la base de datos)
La última línea arrojará el
InvalidOperationException
porque dbContext no ha deshabilitado la carga diferida y el código está accediendo a la propiedad de navegación de Mascotas después de que el Contexto haya sido eliminado por la instrucción de uso.Depuración
¿Cómo encuentra la fuente de esta excepción? Además de mirar la excepción en sí, que se lanzará exactamente en el lugar donde ocurre, se aplican las reglas generales de depuración en Visual Studio: coloque puntos de interrupción estratégicos e inspeccione sus variables , ya sea pasando el mouse sobre sus nombres, abriendo un ( Rápido) Mire la ventana o use los diversos paneles de depuración como Locales y Autos.
Si desea averiguar dónde se establece o no la referencia, haga clic con el botón derecho en su nombre y seleccione "Buscar todas las referencias". Luego puede colocar un punto de interrupción en cada ubicación que solicite datos y ejecutar su programa con el depurador adjunto. Cada vez que el depurador se interrumpe en dicho punto de interrupción, debe determinar si su propiedad de navegación debería haberse rellenado o si los datos solicitados son necesarios.
Formas de evitar
Deshabilitar carga diferida
Pros: en lugar de lanzar la InvalidOperationException, la propiedad será nula. Acceder a propiedades de nulo o intentar cambiar las propiedades de esta propiedad generará una NullReferenceException .
Cómo solicitar explícitamente el objeto cuando sea necesario:
En el ejemplo anterior, Entity Framework materializará la mascota además de la persona. Esto puede ser ventajoso porque es una sola llamada a la base de datos. (Sin embargo, también puede haber grandes problemas de rendimiento dependiendo de la cantidad de resultados devueltos y la cantidad de propiedades de navegación solicitadas, en este caso, no habría penalización de rendimiento porque ambas instancias son solo un registro y una combinación).
o
En el ejemplo anterior, Entity Framework materializará la mascota independientemente de la persona al hacer una llamada adicional a la base de datos. De forma predeterminada, Entity Framework rastrea los objetos que ha recuperado de la base de datos y, si encuentra propiedades de navegación que coinciden, se rellenará automáticamente estas entidades. En este caso, debido a que el
PetId
en elPerson
objeto coincide con elPet.Id
, Entity Framework asignará elPerson.Pet
que elPet
valor recuperado, antes de que se le asigna el valor de la variable de mascota.Siempre recomiendo este enfoque, ya que obliga a los programadores a comprender cuándo y cómo el código solicita datos a través de Entity Framework. Cuando el código arroja una excepción de referencia nula en una propiedad de una entidad, casi siempre puede estar seguro de que no ha solicitado explícitamente esos datos.
fuente
Es una respuesta muy tardía, pero resolví el problema desactivando la carga diferida:
fuente
En mi caso, estaba pasando todos los modelos 'Usuarios' a la columna y no estaba mapeado correctamente, así que simplemente pasé 'Users.Name' y lo arregló.
fuente
La mayoría de las otras respuestas apuntan a una carga ansiosa, pero encontré otra solución.
En mi caso, tenía un objeto EF
InventoryItem
con una colección deInvActivity
objetos secundarios.Y como estaba sacando de la colección de objetos secundarios en lugar de una consulta de contexto (con
IQueryable
), laInclude()
función no estaba disponible para implementar una carga ansiosa. Entonces, en cambio, mi solución fue crear un contexto desde el que utilicéGetLatestActivity()
yattach()
el objeto devuelto:Por lo tanto, no está atrapado con la carga ansiosa.
fuente
Si está utilizando ASP.NET Core y asombro por la que recibe este mensaje en uno de sus métodos asincrónicos controlador, asegúrese de que regrese un
Task
lugar devoid
- ASP.NET dispone núcleo de inyección presenta contextos.(Estoy publicando esta respuesta ya que esta pregunta ocupa un lugar destacado en los resultados de búsqueda de ese mensaje de excepción y es un problema sutil, tal vez sea útil para las personas que lo buscan en Google).
fuente