2011-04-05 16 views
9

Pido disculpas por la falta de detalles en esta pregunta; lo primero que necesito ayuda es saber dónde buscar para obtener más detalles.C# Entity Framework 4 Propiedades de navegación que provocan un rendimiento lento en commit

tengo un problema con propiedades enity marco 4 de navegación aparentemente provocar pérdidas de rendimiento en la comisión de cambios:

this.ObjectContext.SaveChanges(); 

está tomando más de 30 segundos cuando una de las propiedades de navegación (tabla Receipts) contiene alrededor de 8000 filas (que no hay muchos, así que debería estar bien).

He utilizado el generador de perfiles de SQL y puedo ver que EF emite un SELECT * FROM recibos y que es muy lento:

exec sp_executesql N'SELECT 
[Extent1].[Id] AS [Id], 
// full field list cut for brevity 
FROM [dbo].[Receipts] AS [Extent1] 
WHERE [Extent1].[WarehouseId] = @EntityKeyValue1', 
N'@EntityKeyValue1 int',@EntityKeyValue1=1 

En el momento en que ni siquiera se puede ver por qué necesita seleccione todas las filas de esta tabla cuando se invoque ObjectContext.SaveChanges().

No necesita insertar 1 fila en esta tabla, pero eso no explica por qué selecciona primero todo y no explica por qué esa selección tarda tanto (la misma consulta toma < 1 segundo en consulta gerente)

Así que mi pregunta en este momento - no sé exactamente cuál es el problema todavía es - es:

  • Dónde/cómo puedo buscar más información sobre el problema? No puedo depurar en ObjectContext.SaveChanges(), así que no sé qué está sucediendo dentro de él.
  • ¿Por qué EF intentará seleccionar * de Recibos?
  • ¿Por qué es tan lento? La misma consulta exacta copia + pega en gestor de consulta es casi instantáneo

EDIT:

he confirmado que es el código de recibo que es lento comentando la llamada a este método:

private void AddReceipt(PurchaseInvoice invoice, 
           PurchaseInvoiceLine invoiceLine) 
    { 
     if (invoice != null && invoiceLine != null) 
     { 
      Product product = invoiceLine.Product; 
      if (product != null) 
      { 
       Receipt receipt = new Receipt{ foo = bar }; 
       WarehouseDetail detail = new WarehouseDetail{ foo = bar }; 
       receipt.WarehouseDetails.Add(detail); 
       invoice.Receipts.Add(receipt); 
      } 
     } 
    } 

Pero todavía no puedo ver por qué esto causa que EF emita esa consulta * seleccionada.

Creo que podría ser un problema de carga diferida causado por invoice.Receipts.Add(receipt). Porque antes de esa línea, la factura. Recibos está vacía, y para agregar. Agregar a los recibos, primero debe cargar la colección. PERO eso no explica por qué está seleccionando por warehouseId = 1, cuando debería seleccionarse por el invoiceId.

EDIT 2:

He "fija" el problema mediante la sustitución del código de EF en este método con comandos directos SQL. Esta no es una gran idea. No debería lanzar SQL cuando tengo un ORM perfectamente bueno. Pero en este momento todavía no entiendo por qué EF corría el selecto * consulta

private void AddReceipt(PurchaseInvoice invoice, 
           PurchaseInvoiceLine invoiceLine) 
    { 
     if (invoice != null && invoiceLine != null) 
     { 
      Product product = invoiceLine.Product; 
      if (product != null) 
      { 
       Receipt receipt = new Receipt{ foo = bar }; 
       WarehouseDetail detail = new WarehouseDetail{ foo = bar }; 
       int id = SqlHelper.AddWarehouseDetail(detail); 
       receipt.WarehouseDetailId = id; 
       SqlHelper.AddReceipt(receipt); 
      } 
     } 
    } 

Respuesta

1

Como se trata de una pieza de inserción, que refresca su objeto, seleccionando el valor de nuevo y repoblar el objeto.Ahora voy a responder a sus preguntas que expuso:

  1. No debería ser necesario para depurar en lugar de SaveChanges(), lo que se ve probablemente no tendría mucho sentido de todos modos.

  2. En realidad no está haciendo un select * from Receipts. Está haciendo un select * from Receipts where WarehouseId = 1. Por lo tanto, por alguna razón su objeto es extraer todos los recibos para el Almacén con el Id de 1.

  3. Esto podría depender de tantas cosas, que realmente no puede entrar en él ahora. Pero un lugar para comenzar es verificar la frecuencia de ping entre su cuadro de aplicación y su cuadro de db. También verifique que la memoria RAM no esté llena en el cuadro db. Ahí es donde comenzaría, y ese es el problema habitual para lo que estás describiendo.

Una buena herramienta para depurar EF es el EF Profiler. http://efprof.com Esto te ayudará mucho más que SQL Profiler.

+0

+1 por sugerir efprof.com - No era consciente de esto. -1 por el costo, $ 305? Wow –

+0

Re a su punto n. ° 2. Intento encontrar la razón: probablemente es allí donde radica el problema. Encontré que la propiedad de navegación no se estaba utilizando correctamente, pero arreglar esto no ha eliminado la consulta * select –

+0

He encontrado dónde sucede comentando cosas hasta que funcionó. Pero no puedo ver en el código por qué EF emite la consulta de selección. –

1

Su problema es con la "Propiedad de navegación" en su entidad "Almacén". Eliminar esta propiedad de navegación. La relación seguirá allí, pero ya no consultará todos los recibos con ese depósito cuando cree una entidad de recepción. Tuve el mismo problema y esto resolvió mi problema.

+0

¿Puedes por favor elaborar? Este problema aún no se ha resuelto (tiene una "solución" aplicada mediante el uso de instrucciones SQL directas). Todas mis clases de POCO se autogeneran, por lo que contienen una propiedad de navegación para cada relación de FK. ¿Tiene una URL para una página que describe la eliminación de las propiedades de navegación? (por ejemplo, ¿cómo puedo averiguar qué recibo. Warehouse es cuando ya no tengo la propiedad). Gracias –

0

¿Tiene la carga diferida activada? Si es así, activará consultas para las tablas WarehouseDetails y Receipts cuando acceda a las propiedades de navegación relacionadas. Siempre me aseguro de que la carga diferida esté apagada para no generar inadvertidamente consultas.

Cuestiones relacionadas