linq entity framework c#




L'entità non può essere costruita in una query LINQ to Entities (9)

Esiste un tipo di entità chiamato prodotto generato dal framework di entità. Ho scritto questa domanda

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

Il seguente codice genera il seguente errore:

"L'entità o il tipo complesso Shop.Product non può essere costruito in una query LINQ to Entities"

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

Ma quando uso select p invece di select new Product { Name = p.Name}; funziona correttamente

Come posso preformare una sezione di selezione personalizzata?


È possibile proiettare in un tipo anonimo e quindi da esso al tipo di modello

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 : Sarò un po 'più specifico dato che questa domanda ha ottenuto molta attenzione.

Non è possibile proiettare direttamente nel tipo di modello (restrizione EF), quindi non c'è modo di aggirarlo. L'unico modo è di proiettare in un tipo anonimo (1a iterazione), quindi in un modello (seconda iterazione).

Tieni anche presente che quando si caricano parzialmente entità in questo modo, non possono essere aggiornate, quindi devono rimanere separate, così come sono.

Non ho mai capito completamente perché questo non è possibile, e le risposte su questo thread non danno forti ragioni contro di esso (principalmente parlando di dati parzialmente caricati). È corretto che l'entità di stato parzialmente caricata non possa essere aggiornata, ma, quindi, questa entità verrebbe distaccata, quindi i tentativi accidentali di salvarli non sarebbero possibili.

Considera il metodo che ho usato sopra: abbiamo ancora un'entità modello parzialmente caricata come risultato. Questa entità è distaccata.

Considera questo codice (desiderio di esistere) possibile:

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

Questo potrebbe anche portare a un elenco di entità distaccate, quindi non avremmo bisogno di fare due iterazioni. Un compilatore sarebbe intelligente nel vedere che AsNoTracking () è stato usato, il che risulterà in entità distaccate, quindi potrebbe permetterci di farlo. Se, tuttavia, AsNoTracking () è stato omesso, potrebbe generare la stessa eccezione che sta generando ora, per avvertirci che dobbiamo essere abbastanza specifici sul risultato che vogliamo.


È possibile risolvere questo problema utilizzando Data Transfer Objects (DTO).

Questi sono un po 'come i viewmodels in cui inserisci le proprietà di cui hai bisogno e puoi mapparle manualmente nel controller o utilizzando soluzioni di terze parti come AutoMapper.

Con DTO puoi:

  • Rendi i dati serializzabili (Json)
  • Sbarazzati di riferimenti circolari
  • Riduci il networktraffic lasciando le proprietà che non ti servono (viewmodelwise)
  • Usa l'objectflattening

Ho imparato questo a scuola quest'anno ed è uno strumento molto utile.


Ecco un modo per farlo senza dichiarare una classe adizionale:

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;
}

Tuttavia, questo deve essere utilizzato solo se si desidera combinare più entità in una singola entità. La funzionalità di cui sopra (semplice prodotto per la mappatura del prodotto) è fatta in questo modo:

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;
}

In molti casi, la trasformazione non è necessaria. Pensa al motivo per cui vuoi che il tipo sia fortemente elencato e valuta se desideri solo i dati, ad esempio, in un servizio web o per visualizzarlo. Non importa il tipo. Hai solo bisogno di sapere come leggerlo e controllare che sia identico alle proprietà definite nel tipo anonimo che hai definito. Questo è lo scenario di ottimizzazione, causa di qualcosa che non ha bisogno di tutti i campi di un'entità, e questo è il motivo per cui esiste un tipo anonimo.

Un modo semplice è questo:

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

Non è possibile (e non dovrebbe essere possibile) proiettare su un'entità mappata. Puoi, tuttavia, proiettare su un tipo anonimo o su un DTO :

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

E il tuo metodo restituirà un elenco di DTO.

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

Puoi usare questo e dovrebbe funzionare -> Devi usare toList prima di fare il nuovo elenco usando select:

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

Un altro modo semplice :)

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;
}

aggiungi solo AsEnumerable ():

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

se si sta eseguendo Linq to Entity non è possibile utilizzare ClassType con new nella chiusura select della query only anonymous types are allowed (new without type)

dai un'occhiata a questo frammento del mio progetto

//...
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

di voi ha aggiunto la new keyword in Seleziona chiusura anche sulle complex properties che otterrete questo errore

quindi remove i ClassTypes from new parola chiave su Linq to Entity query Linq to Entity ,,

perché verrà trasformato in istruzione sql ed eseguito su SqlServer

quindi quando posso usare new with types chiusura select ?

puoi usarlo se hai a che fare 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 

dopo aver eseguito ToList su query è diventato in memory collection modo da poter utilizzare new ClassTypes in select





entity-framework