Hace unos días @fisica3 intentaba migrar un proyecto en LINQ to SQL a Entity Framework 4. El problema surgía cuando intentaba agregar al modelo una función SQL Server del tipo Composable.
Este tipo de funciones no se pueden mapear en un modelo de entidades, para hacer uso de estas hay que construir el Query con Entity SQL y utilizar las funciones, por ejemplo:
1: using (var context = new ObjectContext("Name=Entities"))
2: {
3: ObjectQuery<EntidadResult> query = context.CreateQuery<EntidadResult>
4: (@"select value c.Nombre, Model.Store.GetApellidos(c.Apellido1, c.Apellidos2) from Entities.Clientes as c");
5:
6: ObjectResult<EntidadResult> result = query.Execute(MergeOption.NoTracking);
7:
8: foreach (var item in result)
9: {
10: Console.WriteLine("{0} {1}", item.Nombre, item.Apellidos);
11: }
12: }
El problema se produce si la función que queremos utilizar es parte de la condición de ordenación, la idea es utilizar una función que devuelve un GUID aleatorio para que la consulta se ordene aleatoriamente.
1: CREATE FUNCTION [dbo].[GetNewId]()
2: RETURNS uniqueidentifier
3: AS
4: BEGIN
5: RETURN (SELECT ID FROM RandomView)
6: END
7:
8: CREATE VIEW [dbo].[RandomView]
9: AS
10: SELECT NEWID() As ID
Si creamos un DataContext con LINQ to SQL y mapeamos la función GetNewId en nuestro modelo, tenemos la posibilidad de realizar nuestra consulta utilizando como ordenación el valor devuelto por la función.
1: using (var context = new MusicaDataClassesDataContext())
2: {
3: var canciones = from c in context.Canciones
4: orderby context.GetNewId()
5: select c;
6:
7: foreach (var item in canciones)
8: {
9: Console.WriteLine("{0} {1}", item.CancionId, item.Album);
10: }
11: }
Entonces, ¿cómo podemos realizar esta consulta con Entity Framework?.
Entity Framework nos permite hacer uso de la expresión LET, que se utiliza para introducir una variable en el ámbito que puede ser utilizado por las siguientes cláusulas de consulta. Similar a las variables locales en un cuerpo de método, esto le da una manera de evitar evaluar una expresión común de varias veces por almacenarlo en una variable. Esto puede ser muy útil incluso en consultas mucho más simples.
Podemos crearnos una consulta con la expresión LET que contengan un valor aleatorio y este sería utilizado para la ordenación (algo parecido a la función que utilizamos en LINQ to SQL).
1: using (var context = new MusicaEntities())
2: {
3: var musica = from p in context.Canciones
4: let guid = Guid.NewGuid()
5: orderby guid
6: select p;
7:
8: foreach (var item in musica)
9: {
10: Console.WriteLine("{0} - {1}", item.CancionId, item.Album);
11: }
12: }
Entity Framework transforma el query anterior, con el let guid = Guid.NewGuid(), en la siguiente sentencia T-SQL, que contiene un subquery con la generación de nuestro GUID.
1: SELECT
2: [Project1].[CancionId] AS [CancionId], [Project1].[Artista] AS [Artista],
3: [Project1].[Album] AS [Album], [Project1].[Titulo] AS [Titulo], [Project1].[AñoAlbum] AS [AñoAlbum],
4: [Project1].[AñoRanking] AS [AñoRanking], [Project1].[Ubicacion] AS [Ubicacion], [Project1].[Ranking99] AS [Ranking99]
5: FROM ( SELECT
6: [Extent1].[CancionId] AS [CancionId], [Extent1].[Artista] AS [Artista],
7: [Extent1].[Album] AS [Album], [Extent1].[Titulo] AS [Titulo],
8: [Extent1].[AñoAlbum] AS [AñoAlbum], [Extent1].[AñoRanking] AS [AñoRanking],
9: [Extent1].[Ubicacion] AS [Ubicacion], [Extent1].[Ranking99] AS [Ranking99],
10: NEWID() AS [C1]
11: FROM [dbo].[Canciones] AS [Extent1]
12: ) AS [Project1]
13: ORDER BY [Project1].[C1] ASC
Como vemos en la consulta transact, la función del CLR Guid.NewGuid se ha transformado en un NEWID() de T-SQL, con lo que se realiza la ordenación por ese campo aleatorio por fila.
Aunque no podamos utilizar la función que nos devuelve un valor aleatorio del tipo GUID, Entity Framework tiene la herramienta necesaria para realizar este método sin necesidad de utilizar la función.
Saludos a todos…