2012-08-26 31 views
5

Soy nuevo en linq. Necesito ejecutar una consulta que une dos columnas (AnonymousUser.AnonymousId siendo uniqueidentifier y comment.UserId siendo nvarchar(100)), algo así como a continuación:linq join on guid and string column

 using (CommentEntities db = new CommentEntities()) 
     { 
      // filteredComments is a query that is not run until the next .ToList() 
      IQueryable<Comment> filteredComments = this.CommentGetList(...); 
      var query = from comment in filteredComments 
         // following line is the syntax error, because columns' types don't match 
         join user in db.AnonymousUsers on comment.UserId equals user.AnonymousId into gj 
         from userNull in gj.DefaultIfEmpty() 
         select new CommentWithName 
         { 
          Comment = comment, 
          UserId = comment.UserId, 
          FirstName = (userNull == null ? "" : userNull.Name), 
          LastName = "", 
          Email = (userNull == null ? "" : userNull.Email) 
         }; 
      return query.ToList(); 
     } 

En primer lugar yo estaba feliz de escribir la consulta con .ToString()! Como resulta que el marco de la entidad no sabe cómo traducirlo a sql. Lo mismo es cierto para Guid.Parse(string). ¡Tampoco se puede usar new Guid(string) en linq a entidades (solo se permiten constructores sin parámetros)!

¡Después de buscar, descubrí que no es posible hacerlo en EF 4.0! Migré mi código a un procedimiento almacenado y no estoy muy contento con él.

¿Es posible decirle a entity framework que use un CAST en SQL?

¿Hay alguna solución a este problema? ¿Hay alguna manera de que pueda traer la lógica en el código?

NOTA: Tengo la intención de hacerlo en GO. De lo contrario, una solución posible es obtener Entidades de la primera tabla, y poner los Id. En una lista y obtener entidades de la segunda tabla.

+0

Si 'comment.UserId' es una representación de cadena de un GUID, ¿sería más fácil convertir esa columna en un identificador único también? Puede ser una solución mejor que tener el Entity Framework intentando hacer esto para ti en SQL. – mclark1129

+0

Lamentablemente, no siempre es GUID. Puede ser un 'Guid' o' int', según el tipo de usuario. – Ashkan

+0

¿Intentó usar ['Guid.Parse (cadena)'] (http://stackoverflow.com/a/8067647/484214) en lugar de 'nueva Guid (cadena)'? –

Respuesta

0

llama a List() antes de aplicar esos métodos. Al igual que:

var Product = db.Products.Where(p => p.ProductId == Guid.Parse("B4E913F9-166C-49BA-AADE-6DB889D1756F")).Single(); 

arrojaría una

C# LINQ a Entidades no reconoce el método de método "System.Guid Parse" (System.String)', y este método no se puede traducir en una tienda expresión

Pero esto funciona:

var Product = db.Products.ToList().Where(p => p.ProductId == Guid.Parse("B4E913F9-166C-49BA-AADE-6DB889D1756F")).Single() 

PS: creo que tú perderá lazyloading pero puede hacer eagerloading con .Include antes de llamar a .ToList().

+0

sería una buena idea usar carga ansiosa si es aplicable a dos tablas sin relación. P.S: no hay relación entre las tablas Comentario y Usuario anónimo – Ashkan

+2

Al final, se llevará a toda la lista a la memoria con esta opción. Solo haga esto si la tabla de productos es pequeña. –

+0

Ninguna tabla de comentarios es una tabla muy grande ... – Ashkan

0

Si su list es la lista de objetos que podría convertirlo en el tipo que ha GUID como identificador, en primer lugar crear nuevo tipo anónimo y luego filtrarla base sobre UserId, seguro UserId que es de tipo int, suele incluir en los unen:

 int output = 0; 

    var secondList = list.Where(x=>!int.TryParse(x.UserID, out output)) 
        .Select(x=>new {Comment = x, ID = new Guid(x.UserID)) 
        .ToList(); 

Ahora puede ejecutar su consulta en db utilizando secondList.

+0

No mencioné que 'list' es del tipo' IQueryable '. – Ashkan

+1

Lo que quiere decir es que es un elemento db, en este caso me gustaría utilizar procedimientos almacenados. –

+0

+1. Entonces, ¿aceptas que EF no puede hacer esto? ¿qué hay de las versiones más nuevas de EF? – Ashkan