2011-02-28 18 views
26

estoy en el proceso de escribir un gestor de consulta para una aplicación de Windows Forms que, entre otras cosas, tiene que ser capaz de entregar resultados de búsqueda en tiempo real para el usuario, ya que está entrando en una consulta (piense en los resultados en vivo de Google, aunque obviamente en un entorno de cliente grueso en lugar de la web). Dado que los resultados tienen que empezar a llegar, ya que el usuario escribe, la búsqueda se vuelven más y más específico, por lo que me gustaría ser capaz de cancelar una consulta si todavía está ejecutando mientras que el usuario ha introducido información más específica (ya que los resultados serían simplemente descartarlo, de todos modos).Cancelación de una consulta de Entity Framework

Si esto fuera normal ADO.NET, obviamente podría usar la función DbCommand.Cancel y terminarla, pero estamos usando EF4 para nuestro acceso a los datos y no parece haber una manera obvia de cancelar una consulta. Además, la apertura de System.Data.Entity en el reflector y mirando a EntityCommand.Cancel muestra un cuerpo de método vacío desalentador, a pesar de la docs alegando que llamar a esto sería pasarlo a la función correspondiente Cancel del comando de proveedor.

He considerado simplemente dejar que la consulta existente se ejecute y gire en un nuevo contexto para ejecutar la nueva búsqueda (y descartar la consulta una vez que termine), pero no me gusta la idea de que un solo cliente tenga una multitud de conexiones de bases de datos abiertas que ejecutan consultas paralelas cuando solo estoy interesado en los resultados de la más reciente.

Todo esto me está dando lugar a creer que simplemente no hay forma de cancelar una consulta de EF una vez que ha sido enviado a la base de datos, pero estoy esperando que alguien aquí podría ser capaz de señalar algo he pasado por alto.

TL/DR Versión: ¿Es posible cancelar una consulta EF4 que se está ejecutando actualmente?

+0

He pedido a dudas acerca de este problema en el foro de MSDN: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/ d5ea8036-73e5-4566-9407-fa7a6a5fca3c Esta pregunta original está vinculada.Con suerte, alguien de MS brindará otra solución. –

Respuesta

12

Parece que has encontrado algunos errores en la FE, pero cuando lo informe a MS no será considerado como error en la documentación. De todos modos, no me gusta la idea de interactuar directamente con EntityCommand. Aquí está mi ejemplo cómo matar consulta actual:

var thread = new Thread((param) => 
    { 
     var currentString = param as string; 

     if (currentString == null) 
     { 
      // TODO OMG exception 
      throw new Exception(); 
     } 

     AdventureWorks2008R2Entities entities = null; 
     try // Don't use using because it can cause race condition 
     { 
      entities = new AdventureWorks2008R2Entities(); 

      ObjectQuery<Person> query = entities.People 
       .Include("Password") 
       .Include("PersonPhone") 
       .Include("EmailAddress") 
       .Include("BusinessEntity") 
       .Include("BusinessEntityContact"); 
      // Improves performance of readonly query where 
      // objects do not have to be tracked by context 
      // Edit: But it doesn't work for this query because of includes 
      // query.MergeOption = MergeOption.NoTracking; 

      foreach (var record in query 
       .Where(p => p.LastName.StartsWith(currentString))) 
      { 
       // TODO fill some buffer and invoke UI update 
      } 
     } 
     finally 
     { 
      if (entities != null) 
      { 
       entities.Dispose(); 
      } 
     } 
    }); 

thread.Start("P"); 
// Just for test 
Thread.Sleep(500); 
thread.Abort(); 

Es resultado de mi forma de tocar con si después de 30 minutos por lo que probablemente no es algo que debe ser considerado como solución final. Lo estoy publicando para obtener al menos algunos comentarios con posibles problemas causados ​​por esta solución. Los puntos principales son:

  • Contexto con la mano dentro del hilo
  • resultado no es rastreado por el contexto
  • Si matas a la consulta hilo se termina y está dispuesto contexto (conexión liberado)
  • Si matas el hilo antes de comenzar un nuevo hilo debe usar todavía una conexión.

Comprobé que la consulta se inició y finalizó en SQL Profiler.

Editar:

BTW. Otro enfoque simplemente dejar de consulta actual es la enumeración en el interior:

public IEnumerable<T> ExecuteQuery<T>(IQueryable<T> query) 
{ 
    foreach (T record in query) 
    { 
     // Handle stop condition somehow 
     if (ShouldStop()) 
     { 
      // Once you close enumerator, query is terminated 
      yield break; 
     } 
     yield return record; 
    } 
} 
+0

Interesante; como punto de aclaración, no estaba sugiriendo que interactuar con 'EntityCommand' era el enfoque correcto, pero el hecho de que el cuerpo del método esté vacío significaba que la probabilidad de que sea posible en un nivel aún más alto era escasa. Este es un escenario interesante y puede funcionar al final, pero en este momento sí necesito un seguimiento de cambios si es posible, por lo que deshacerme del contexto no es algo que esté dispuesto a hacer. Si no puedo encontrar una alternativa, lo aceptaré. –

+0

@ Adam: Bien, voy a pensar en el escenario con seguimiento de cambios mañana porque tiene nuevas consecuencias: incluso si cancela la consulta, todas las instancias cargadas ya serán rastreadas por contexto. Mi sugerencia inicial es un nuevo contexto para cada búsqueda, pero tengo que pensarlo. –

+0

No estoy realmente interesado en cancelar una consulta mientras se está cargando. Eso se logra fácilmente con el enfoque que tienes arriba. Lo que estoy buscando es cancelarlo durante la etapa * query * (mientras se está ejecutando en el lado del servidor). –

Cuestiones relacionadas