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


Existe un tipo de entidad llamado product que es generado por entity framework. He escrito esta consulta

public IQueryable<Product> 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 tienda de tipo entidad o complejo.El producto no puede construirse en un LINQ to Entities query "

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

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

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

Author: Gilad Green, 2011-03-16

13 answers

Usted 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<ProductDTO> GetProducts(int categoryID)
{
    return (from p in db.Products
            where p.CategoryID == categoryID
            select new ProductDTO { Name = p.Name }).ToList();
}
 337
Author: Yakimych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-11 02:40:39

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

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

Edit : Voy a ser un poco más específico ya que esta pregunta recibió mucha atención.

No se puede proyectar en el tipo de modelo directamente (restricción EF), por lo que no hay forma de evitarlo. La única manera es proyectar en tipo anónimo (1a iteración), y luego en tipo modelo (2a iteración).

También tenga en cuenta que cuando carga parcialmente entidades de esta manera, no pueden estén actualizados, para que permanezcan desapegados, como son.

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

Considere el método que utilicé anteriormente: todavía tenemos un modelo parcialmente cargado entidad como resultado. Esta entidad está separada.

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

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

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

 241
Author: Goran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-18 09:50:11

Hay otra forma que encontré funciona, tienes que construir una clase que deriva de tu clase de Producto y usarla. Por ejemplo:

public class PseudoProduct : Product { }

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

No estoy seguro si esto está "permitido", pero funciona.

 68
Author: Tomasz Iniewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-28 14:52:04

Aquí hay una manera de hacer esto sin declarar clase adicional:

public List<Product> 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 se puede usar si desea combinar varias entidades en una sola entidad. La funcionalidad anterior (mapeo simple de producto a producto) se hace así:

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

    return products;
}
 33
Author: Bojan Hrnkas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-08 14:55:05

Otra manera simple:)

public IQueryable<Product> 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;
}
 21
Author: Soren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-14 05:28:15

Puedes usar esto y debería estar funcionando > > Debes 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(); 
 3
Author: Mohamed Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-20 08:39:32

Solo agregue AsEnumerable ():

public IQueryable<Product> GetProducts(int categoryID)
{
    return from p in db.Products.AsEnumerable()
           where p.CategoryID== categoryID
           select new Product { Name = p.Name};
}
 2
Author: HamidReza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-06 12:40:39

En respuesta a la otra pregunta que estaba 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 foránea) en la clase Task (aquí llamada 'Incident'). Si no tienes eso, puedes usar una de las otras soluciones publicadas con " AsQueryable ()".

 1
Author: JollyBrackets,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:37

Si está utilizando Entity framework, intente eliminar la propiedad de DbContext que usa su modelo complejo como Entidad Tuve el mismo problema al mapear varios modelos en un viewmodel llamado Entity

public DbSet<Entity> Entities { get; set; }

Eliminar la entrada de DbContext solucionó mi error.

 0
Author: vikas suhag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-25 08:24:37

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

Echa un vistazo a este fragmento de mi proyecto

//...
var dbQuery = context.Set<Letter>()
                .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ó el new keyword en Select closure incluso en el complex properties obtendrá este error

So remove the ClassTypes from new keyword on Linq to Entity queries,,

Porque se transformará en sentencia sql y se ejecutará en SQLServer

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

Puedes usarlo si estás 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 <anonymous type> so we have to convert it so list of <letter>

//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ó en in memory collection para que podamos usar new ClassTypes en select

 0
Author: Basheer AL-MOMANI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-05 17:44:36

Puede resolver esto usando Objetos de transferencia de datos (DTO).

Estos son un poco como viewmodels donde pones las propiedades que necesitas y puedes mapearlas manualmente en tu controlador o usando soluciones de terceros como AutoMapper.

Con DTO puedes :

  • Hacer serializables los datos (Json)
  • Deshacerse de las referencias circulares
  • Reduce networktraffic dejando propiedades que no necesitas (viewmodelwise)
  • Uso objectflattening

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

 0
Author: Jelman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-01 09:44:58

En muchos casos, la transformación no es necesaria. Piense por la razón por la que desea la lista de tipos fuertes 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 comprobar que es idéntico a las propiedades definidas en el tipo anónimo que definió. Ese es el escenario optimun, 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 sencilla es hacer esto:

IEnumerable<object> list = dataContext.Table.Select(e => new { MyRequiredField = e.MyRequiredField}).AsEnumerable();
 0
Author: Sterling Diaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-06 22:57:03

Puedes añadir un numerable a tu colección de la siguiente manera:

public IQueryable<Product> GetProducts(int categoryID)
{
    return from p in db.Products.AsEnumerable()
           where p.CategoryID== categoryID
           select new Product { Name = p.Name};
}
 -2
Author: HamidReza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-07 10:03:16