Tenemos la respuesta a esta contratiempo, o por lo menos eso creemos. Si tienes interrogantes coméntalo y sin dudarlo te ayudaremos
Solución:
Si el ToList()
es parte de su consulta original y no solo se agregó para este ejemplo, luego use LINQ to Objects en la lista resultante para hacer la agregación:
var query = (from t in context.TestData
group t by new DataTypeID = t.DataTypeID, Name = t.Name into g
select new DataTypeID = g.Key.DataTypeID, Name = g.Key.Name, Data = g.AsEnumerable())
.ToList()
.Select (q => new DataTypeID = q.DataTypeID, Name = q.Name, DataValues = q.Data.Aggregate ("", (acc, t) => (acc == "" ? "" : acc + ",") + t.DataValue) );
Probado en LINQPad y produce este resultado:
Algunas de las respuestas sugieren llamar a ToList() y luego realizar el cálculo como LINQ to OBJECT. Eso está bien para una pequeña cantidad de datos, pero si tengo una gran cantidad de datos que no quiero cargar en la memoria demasiado pronto, ToList() puede no ser una opción.
Por lo tanto, la mejor idea sería procesar/formatear los datos en la capa de presentación y dejar que la capa de acceso a datos solo cargue o guarde los datos sin procesar que le gustan a SQL. Además, en su capa de presentación, lo más probable es que esté filtrando los datos por paginación, o tal vez esté mostrando una fila en la página de detalles, por lo que los datos que cargará en la memoria probablemente sean más pequeños que los datos que cargue desde la base de datos. . (Su situación/arquitectura puede ser diferente… pero estoy diciendo que lo más probable).
Yo tenía un requisito similar. Mi problema era obtener la lista de elementos del objeto Entity Framework y crear un formato string (valor separado por comas)
-
Creé una propiedad en mi modelo de vista que contendrá los datos sin procesar del repositorio y al completar esa propiedad, la consulta LINQ no será un problema porque simplemente está consultando lo que SQL entiende.
-
Luego, creé una propiedad get only en mi ViewModel que lee esa propiedad de entidad Raw y formatea los datos antes de mostrarlos.
public class MyViewModel public IEnumerable
RawChildItems get; set; public string FormattedData get if (this.RawChildItems == null) return string.Empty; string[] theItems = this.RawChildItems.ToArray(); return theItems.Length > 0 ? string.Format("0 ( 1 )", this.AnotherRegularProperty, String.Join(", ", theItems.Select(z => z.Substring(0, 1)))) : string.Empty;
Ok, de esa manera, cargué los datos de LINQ a Entity a este modelo de vista fácilmente sin llamar a ToList().
Ejemplo:
IQueryable myEntities = _myRepository.GetData();
IQueryable viewModels = myEntities.Select(x => new MyViewModel() RawChildItems = x.MyChildren )
Ahora, puedo llamar a la propiedad FormattedData de MyViewModel en cualquier momento cuando lo necesite y Getter se ejecutará solo cuando se llame a la propiedad, que es otro beneficio de este patrón (procesamiento diferido).
Una recomendación de arquitectura: Recomiendo encarecidamente mantener la capa de acceso a datos alejada de todo formato o lógica de vista o cualquier cosa que SQL no entienda.
Sus clases de Entity Framework deben ser POCO simples que puedan asignarse directamente a una columna de base de datos sin ningún asignador especial. Y su capa de acceso a datos (por ejemplo, un repositorio que obtiene datos de su DbContext usando LINQ to SQL) debe obtener solo los datos que se almacenan directamente en su base de datos. Sin lógica adicional.
Luego, debe tener un conjunto dedicado de clases para su capa de presentación (por ejemplo, ViewModels) que contendrá toda la lógica para formatear los datos que a su usuario le gusta ver. De esa manera, no tendrá que luchar con la limitación de Entity Framework LINQ. Nunca pasaré mi modelo de Entity Framework directamente a la Vista. Tampoco dejaré que mi capa de acceso a datos cree el ViewModel por mí. La creación de ViewModel se puede delegar a su capa de servicio de dominio o capa de aplicación, que es una capa superior a su capa de acceso a datos.
Gracias a moi_meme por la respuesta. Lo que esperaba hacer NO ES POSIBLE con LINQ to Entities. Como han sugerido otros, debe usar LINQ to Objects para obtener acceso a string métodos de manipulación.
Vea el enlace publicado por moi_meme para más información.
Actualización 27/08/2018 – Enlace actualizado (nuevamente) – https://web.archive.org/web/20141106094131/http://www.mythos-rini.com/blog/archives/4510
Y dado que estoy recibiendo críticas por una respuesta de solo enlace de hace 8 años, lo aclararé en caso de que la copia archivada desaparezca algún día. La esencia básica de esto es que no puedes acceder string.join en consultas EF. Debe crear la consulta LINQ y luego llamar a ToList() para ejecutar la consulta en la base de datos. Luego tiene los datos en la memoria (también conocido como LINQ to Objects), para que pueda acceder string.unirse.
El código sugerido del enlace de referencia anterior es el siguiente:
var result1 = (from a in users
b in roles
where (a.RoleCollection.Any(x => x.RoleId = b.RoleId))
select new
UserName = a.UserName,
RoleNames = b.RoleName)
);
var result2 = (from a in result1.ToList()
group a by a.UserName into userGroup
select new
UserName = userGroup.FirstOrDefault().UserName,
RoleNames = String.Join(", ", (userGroup.Select(x => x.RoleNames)).ToArray())
);
El autor sugiere además reemplazar string.join con agregado para un mejor rendimiento, así –
RoleNames = (userGroup.Select(x => x.RoleNames)).Aggregate((a,b) => (a + ", " + b))
Comentarios y puntuaciones del artículo
Finalizando este artículo puedes encontrar las crónicas de otros usuarios, tú aún tienes la libertad de mostrar el tuyo si lo crees conveniente.