6

Sto postando questo di più perché mi piacerebbe saperne di più, perché il mio work-around è stato fondamentalmente quello di evitare di usare LINQ to Entities! Sarebbe bello se potessi usarlo però. Quindi, se qualcuno mi può illuminare ..LINQ to Entities ToString() - Nessuna delle soluzioni proposte funziona?

Sto lavorando a un'applicazione ASP.Net MVC 3 (la mia prima) utilizzando il primo Entity Framework come mio modello di dati. Sarà un negozio online e sto lavorando al controller 'Admin' dove, come amministratore, sarai in grado di modificare i prodotti ecc. Quando si tratta di aggiungere un nuovo prodotto, è necessario specificare una categoria, il che significa che elenco a discesa di categorie.

Ho iniziato restituendo una raccolta di categorie IEnumerable nel ViewBag, in base alle informazioni che ho trovato here. Questo mi è sembrato un modo davvero carino di approcciare le cose.

Ma ho ricevuto lo stesso errore che vedrete qui sotto. Quindi, seguendo un suggerimento che ho letto online, ho creato un modello separato appositamente per creare e modificare prodotti esistenti. La raccolta Categorie viene utilizzata per creare un elenco a discesa nella vista.

public class ProductModel 
{ 
    public int Id { get; set; } 
    public int CategoryId { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public double Price { get; set; } 
    public bool IsVisible { get; set; } 

    public IEnumerable<SelectListItem> Categories 
    { 
     get 
     { 
      return new DataAccess() 
       .Categories 
       .OrderBy(c => c.Description) 
       .Select(c => new SelectListItem 
        { 
         Value = c.Id.ToString(), 
         Text = c.Description 
        }); 
     } 
    } 
} 

Il risultato è il seguente messaggio di errore: "LINQ to Entities non riconosce il metodo 'System.String ToString()' il metodo, e questo metodo non può essere tradotto in un negozio di espressione.". Una soluzione online proposta consisteva nell'utilizzare i metodi SqlFunction forniti da Entity Framework. Così ho provato questo, invece ...

public IEnumerable<SelectListItem> Categories 
    { 
     get 
     { 
      return new DataAccess() 
       .Categories 
       .OrderBy(c => c.Description) 
       .Select(c => new SelectListItem 
        { 
         Value = SqlFunctions.StringConvert((double)c.Id), 
         Text = c.Description 
        }); 
     } 
    } 

Ma questo si traduce in questo messaggio di errore: "Il metodo specificato 'System.String StringConvert (System.Nullable`1 [System.Double])' del tipo ' System.Data.Objects.SqlClient.SqlFunctions 'non può essere tradotto in un LINQ all'espressione di archivio di entità. ".

Ho anche provato ad aggiungere una proprietà di sola lettura alla classe dati chiamata IdAsString, ma ciò ovviamente rende l'Entity Framework molto infelice!

Alla fine, mi sono reso conto che non valeva la pena tutto il tempo che stavo dedicando a questo, e ho smesso di usare completamente LINQ. Funziona bene, ma sarebbe bello sapere se esiste un modo "corretto" per farlo che funziona davvero!

Questa è la mia soluzione di lavoro corrente:

public IEnumerable<SelectListItem> Categories 
    { 
     get 
     { 
      var dal = new DataAccess(); 
      var categories = dal.Categories; 
      var items = new List<SelectListItem>(); 

      foreach (var category in categories) 
       items.Add(new SelectListItem 
        { 
         Value = category.Id.ToString(), 
         Text = category.Description 
        }); 

      return items; 
     } 
    } 

Quindi, se qualcuno sta già facendo questo e pensano che stanno facendo nel modo "corretto", poi mi piacerebbe sapere cosa ne pensate!

risposta

11

Materializza la query prima di richiamare ToString renderà l'ultima parte una query non linq-to-entities. È possibile ottimizzare ciò selezionando solo l'id e la descrizione, quindi chiamando AsEnumerable e quindi ottenendo gli elenchi di selezione.

return new DataAccess() 
     .Categories 
     .OrderBy(c => c.Description) 
     .AsEnumerable() 
     .Select(c => new SelectListItem 
      { 
       Value = c.Id.ToString(), 
       Text = c.Description 
      }); 
+0

Wow. E 'stato davvero così semplice - grazie !! Ho avuto la sensazione che "dovrebbe" essere semplice! –

+3

Puoi anche usare 'AsEnumerable' invece di' ToList'. L'assegnazione di una lista che verrà elencata solo non ha senso. Con 'AsEnumerable' enumererai ciascun elemento solo una volta, invece di due volte con' ToList'. Se stai restituendo pochi risultati, comunque non ci saranno differenze percettibili. –