2010-03-18 22 views
7

Utilizo LINQ-SQL como mi DAL, luego tengo un proyecto llamado DB que actúa como mi BLL. Varias aplicaciones luego acceden al BLL para leer/escribir datos de la base de datos SQL.¿Cuál es la diferencia entre estas consultas LINQ?

que tienen estos métodos en mi BLL para una tabla en particular:

public IEnumerable<SystemSalesTaxList> Get_SystemSalesTaxList() 
{ 
     return from s in db.SystemSalesTaxLists 
       select s; 
} 

public SystemSalesTaxList Get_SystemSalesTaxList(string strSalesTaxID) 
{ 
    return Get_SystemSalesTaxList().Where(s => s.SalesTaxID == strSalesTaxID).FirstOrDefault(); 
} 

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string strZipCode) 
{ 
    return Get_SystemSalesTaxList().Where(s => s.ZipCode == strZipCode).FirstOrDefault(); 
} 

Todo bastante sencillo que pensaba.

Get_SystemSalesTaxListByZipCode siempre devuelve un valor nulo, incluso cuando tiene un código postal que existe en esa tabla.

Si escribo el método como este, devuelve la fila que quiero:

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string strZipCode) 
{ 
    var salesTax = from s in db.SystemSalesTaxLists 
        where s.ZipCode == strZipCode 
        select s; 

    return salesTax.FirstOrDefault(); 
} 

¿Por qué otro método no producen el mismo resultado, ya que la consulta debe ser idéntico?

Tenga en cuenta que, el Get_SystemSalesTaxList(string strSalesTaxID) sobrecargado devuelve un registro muy bien cuando le doy un SalesTaxID válido.

¿Existe alguna manera más eficiente de escribir estas clases de tipo "ayuda"?

Gracias!

+0

estúpida pregunta - ¿está seguro de que está pasando el Código Postal a 'Get_SystemSalesTaxListByZipCode'? – Oded

+1

El problema es, como se identificó, el 'IEnumerable ' - pero solo estoy gritando para decir "es probable que sea una forma de queja sobre la notación húngara"; p –

Respuesta

7

Esto probablemente se deba a las diferentes formas en que maneja LINQ IEnumerable<T> y IQueryable<T>.

Ha declarado Get_SystemSalesTaxList como devolver . Eso significa que cuando, en la primera muestra de código, aplica el operador Where a los resultados de Get_SystemSalesTaxList, se resuelve con el método de extensión Enumerable.Where. (Tenga en cuenta que lo que importa es el tipo declarado Sí, en tiempo de ejecución se Get_SystemSalesTaxList devolver un IQueryable<SystemSalesTaxList>, pero su declarada tipo -. Lo que ve el compilador - es IEnumerable<SystemSalesTaxList>.) Enumerable.Where corre el predicado .NET especificada por encima del objetivo secuencia. En este caso, itera sobre todos los objetos SystemSalesTaxList devueltos por Get_SystemSalesTaxList, produciendo aquellos en los que la propiedad ZipCode es igual a la cadena de código postal especificada (utilizando el operador .NET String ==).

Pero en su último ejemplo de código, aplica el operador Where al db.SystemSalesTaxList, que se declara como del tipo IQueryable<SystemSalesTaxList>. Entonces, el operador Where de esa muestra se resuelve en Queryable.Where, que traduce la expresión del predicado especificado a SQL y la ejecuta en la base de datos.

Lo que es diferente en los métodos de código postal es que el primero ejecuta la prueba C# s.ZipCode == strZipCode en .NET, y el segundo lo traduce en una consulta SQL WHERE ZipCode = 'CA 12345' (SQL parametrizado realmente pero se entiende la idea). ¿Por qué estos dan diferentes resultados? Es difícil estar seguro, pero el predicado C# == distingue entre mayúsculas y minúsculas, y dependiendo de la configuración de su intercalación, el SQL puede o no distinguir entre mayúsculas y minúsculas. Así que mi sospecha es que strZipCode no coincide con los códigos postales de la base de datos en el caso, pero en la segunda versión la intercalación de SQL Server está suavizando esto.

La mejor solución es probablemente cambiar la declaración de Get_SystemSalesTaxList para devolver IQueryable<SystemSalesTaxList>. El principal beneficio de esto es que significa que las consultas creadas en Get_SystemSalesTaxList se ejecutarán en el lado de la base de datos.Por el momento, sus métodos están retirando TODO en la tabla de la base de datos y filtrándolo en el lado del cliente. Al cambiar la declaración, sus consultas se traducirán a SQL y se ejecutarán de manera mucho más eficiente, y con suerte se resolverá el problema de su código postal.

+0

tiene sentido para mí, y era exactamente el tipo de ¡respuesta que quería obtener al publicar la pregunta! Gracias. – SnAzBaZ

1

El verdadero problema aquí es el uso de IEnumerable<T>, que rompe la "composición" de las consultas; Esto tiene dos efectos:

  • que está leyendo todos (o al menos, más de lo necesario) de su mesa cada vez, incluso si se pide una sola fila
  • está ejecutando LINQ a Objetos normas, por lo mayúsculas y minúsculas se aplica

su lugar, desea estar usando IQueryable<T> dentro de la capa de datos, que le permite combinar varias consultas con adicional Where, OrderBy, Skip, Take, etc., según sea necesario y tienen que construir el TSQL para que coincida (y use las reglas de sensibilidad a mayúsculas y minúsculas de su db)

¿Existe alguna forma más eficiente de escribir estas clases de tipo "ayuda"?

Para más eficiente (menos código de depurar, no corriente de toda la tabla, un mejor uso de la identidad de ruta para cortocircuito búsquedas adicionales (a través de FirstOrDefault etc)):

public IEnumerable<SystemSalesTaxList> Get_SystemSalesTaxList() 
{ 
    return db.SystemSalesTaxLists; 
} 

public SystemSalesTaxList Get_SystemSalesTaxList(string salesTaxID) 
{ 
    return db.SystemSalesTaxLists.FirstOrDefault(s => s.SalesTaxID==salesTaxID); 
} 

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string zipCode) 
{ 
    return db.SystemSalesTaxLists.FirstOrDefault(s => s.ZipCode == zipCode); 
} 
+0

Aunque vea también mi nota aquí (http://stackoverflow.com/questions/2469816/what-is-the-best-way-to-determine-if-table-already-has-record-with-specific-id/ 2469836 # 2469836) para la diferencia entre 'Where (predicate) .FirstOrDefault()' y 'FirstOrDefault (predicate)' entre .NET 3.5/3.5SP1/4.0 –

+0

¡Gracias, no una sino dos excelentes respuestas a mi pregunta! – SnAzBaZ

Cuestiones relacionadas