La entidad no se puede construir en una consulta LINQ to Entities

Hay un tipo de entidad llamado producto que es generado por el marco de la entidad. He escrito esta consulta

public IQueryable GetProducts(int categoryID) { return from p in db.Products where p.CategoryID== categoryID select new Product { Name = p.Name}; } 

El siguiente código arroja el siguiente error:

“La entidad o tipo complejo Shop.Product no se puede construir en una consulta LINQ to Entities”

 var products = productRepository.GetProducts(1).Tolist(); 

Pero cuando uso select p lugar de select new Product { Name = p.Name}; funciona correctamente

¿Cómo puedo preformar una sección de selección personalizada?

No puede (y no debería poder) proyectar en una entidad mapeada. Sin embargo, puede proyectar en un tipo anónimo o en un DTO :

 public class ProductDTO { public string Name { get; set; } // Other field you may need from the Product entity } 

Y su método devolverá una Lista de DTO.

 public List GetProducts(int categoryID) { return (from p in db.Products where p.CategoryID == categoryID select new ProductDTO { Name = p.Name }).ToList(); } 

Puede proyectar en tipo anónimo, y luego desde él al tipo de modelo

 public IEnumerable GetProducts(int categoryID) { return (from p in Context.Set() where p.CategoryID == categoryID select new { Name = p.Name }).ToList() .Select(x => new Product { Name = x.Name }); } 

Editar : voy a ser un poco más específico ya que esta pregunta llamó mucho la atención.

No puede proyectar directamente en el tipo de modelo (restricción EF), por lo que no hay forma de evitar esto. La única forma es proyectar en un tipo anónimo (primera iteración) y luego en el tipo de modelo (segunda iteración).

Tenga en cuenta que cuando carga parcialmente entidades de esta manera, no se pueden actualizar, por lo que deben permanecer separadas, tal como están.

Nunca entendí completamente por qué esto no es posible, y las respuestas en este hilo no dan fuertes razones en contra (principalmente hablando de datos parcialmente cargados). Es correcto que en una entidad de estado parcialmente cargada no se puede actualizar, pero luego, esta entidad se separaría, por lo que los bashs accidentales de guardarlos no serían posibles.

Considere el método que utilicé arriba: todavía tenemos una entidad modelo parcialmente cargada como resultado. Esta entidad está separada.

Considere este posible código (deseo de existir):

 return (from p in Context.Set() where p.CategoryID == categoryID select new Product { Name = p.Name }).AsNoTracking().ToList(); 

Esto también podría dar como resultado una lista de entidades separadas, por lo que no necesitaríamos hacer dos iteraciones. Un comstackdor sería inteligente para ver que AsNoTracking () se ha utilizado, lo que dará como resultado entidades separadas, por lo que podría permitirnos hacer esto. Sin embargo, si se omite AsNoTracking (), podría arrojar la misma excepción que está lanzando ahora, para advertirnos que debemos ser lo suficientemente específicos sobre el resultado que queremos.

Hay otra forma en que encontré trabajo, tienes que construir una clase que derive de tu clase de Producto y usar eso. Por ejemplo:

 public class PseudoProduct : Product { } public IQueryable GetProducts(int categoryID) { return from p in db.Products where p.CategoryID== categoryID select new PseudoProduct() { Name = p.Name}; } 

No estoy seguro de si esto está “permitido”, pero funciona.

Aquí hay una forma de hacerlo sin declarar una clase adicional:

 public List GetProducts(int categoryID) { var query = from p in db.Products where p.CategoryID == categoryID select new { Name = p.Name }; var products = query.ToList().Select(r => new Product { Name = r.Name; }).ToList(); return products; } 

Sin embargo, esto solo debe usarse si desea combinar varias entidades en una sola entidad. La funcionalidad anterior (simple producto a mapeo de producto) se hace así:

 public List GetProducts(int categoryID) { var query = from p in db.Products where p.CategoryID == categoryID select p; var products = query.ToList(); return products; } 

Otra forma simple 🙂

 public IQueryable GetProducts(int categoryID) { var productList = db.Products .Where(p => p.CategoryID == categoryID) .Select(item => new Product { Name = item.Name }) .ToList() .AsQueryable(); // actually it's not useful after "ToList()" :D return productList; } 

Puede usar esto y debería estar funcionando -> Debe usar toList antes de hacer la nueva lista usando select:

 db.Products .where(x=>x.CategoryID == categoryID).ToList() .select(x=>new Product { Name = p.Name}).ToList(); 

solo agregue AsEnumerable ():

 public IQueryable GetProducts(int categoryID) { return from p in db.Products.AsEnumerable() where p.CategoryID== categoryID select new Product { Name = p.Name}; } 

En respuesta a la otra pregunta que fue marcada como duplicada ( ver aquí ), descubrí una solución rápida y fácil basada en la respuesta de Soren:

 data.Tasks.AddRange( data.Task.AsEnumerable().Select(t => new Task{ creator_id = t.ID, start_date = t.Incident.DateOpened, end_date = t.Incident.DateCLosed, product_code = t.Incident.ProductCode // so on... }) ); data.SaveChanges(); 

Nota: Esta solución solo funciona si tiene una propiedad de navegación (clave externa) en la clase Tarea (aquí se llama ‘Incidente’). Si no tiene eso, puede usar una de las otras soluciones publicadas con “AsQueryable ()”.

Si está utilizando Entity Framework, intente eliminar la propiedad de DbContext que utiliza su modelo complejo como Entity I. Tenía el mismo problema al mapear varios modelos en un modelo de vista llamado Entity.

 public DbSet Entities { get; set; } 

Eliminar la entrada de DbContext solucionó mi error.

si está ejecutando Linq to Entity no puede usar ClassType con new en el cierre de select de consulta, only anonymous types are allowed (new without type)

mira este fragmento de mi proyecto

 //... var dbQuery = context.Set() .Include(letter => letter.LetterStatus) .Select(l => new {Title =l.Title,ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated,LetterStatus = new {ID = l.LetterStatusID.Value,NameInArabic = l.LetterStatus.NameInArabic,NameInEnglish = l.LetterStatus.NameInEnglish} }) ^^ without type__________________________________________________________________________________________________________^^ without type 

de usted agregó la new keyword en Seleccionar cierre incluso en las complex properties que recibirá este error

por lo tanto, remove ClassTypes from new palabra clave ClassTypes from new en Linq to Entity consultas de la Linq to Entity ,,

porque se transformará en la statement sql y se ejecutará en SqlServer

Entonces, ¿cuándo puedo usar new with types en select cierre?

puede usarlo si está tratando con LINQ to Object (in memory collection)

 //opecations in tempList , LINQ to Entities; so we can not use class types in select only anonymous types are allowed var tempList = dbQuery.Skip(10).Take(10).ToList();// this is list of  so we have to convert it so list of  //opecations in list , LINQ to Object; so we can use class types in select list = tempList.Select(l => new Letter{ Title = l.Title, ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated, LetterStatus = new LetterStatus{ ID = l.LetterStatus.ID, NameInArabic = l.LetterStatus.NameInArabic, NameInEnglish = l.LetterStatus.NameInEnglish } }).ToList(); ^^^^^^ with type 

después de ejecutar ToList en la consulta, se convirtió in memory collection para que podamos usar new ClassTypes en select

Puede resolver esto utilizando objetos de transferencia de datos (DTO).

Estos son un poco como los modelos de vista donde pone las propiedades que necesita y puede asignarlas manualmente en su controlador o utilizando soluciones de terceros como AutoMapper.

Con DTO puedes:

  • Hacer datos serializables (Json)
  • Deshágase de las referencias circulares
  • Reduzca el tráfico de red dejando propiedades que no necesita (vista en el otro lado)
  • Usar objectflattening

He estado aprendiendo esto en la escuela este año y es una herramienta muy útil.

En muchos casos, la transformación no es necesaria. Piense por la razón por la que desea la Lista de tipo fuerte y evalúe si solo desea los datos, por ejemplo, en un servicio web o para mostrarlos. No importa el tipo. Solo necesita saber cómo leerlo y verificar que sea idéntico a las propiedades definidas en el tipo anónimo que definió. Ese es el escenario optimista, causa algo que no necesita todos los campos de una entidad, y esa es la razón por la que existe el tipo anónimo.

Una forma simple es hacer esto:

 IEnumerable list = dataContext.Table.Select(e => new { MyRequiredField = e.MyRequiredField}).AsEnumerable(); 

puede agregar AsEnumerable a su colección de la siguiente manera:

 public IQueryable GetProducts(int categoryID) { return from p in db.Products.AsEnumerable() where p.CategoryID== categoryID select new Product { Name = p.Name}; }