Problema con la conversione di int in stringa in Linq in entità


202
var items = from c in contacts
            select new ListItem
            {
                Value = c.ContactId, //Cannot implicitly convert type 'int' (ContactId) to 'string' (Value).
                Text = c.Name
            };
var items = from c in contacts
            select new ListItem
            {
                Value = c.ContactId.ToString(), //Throws exception: ToString is not supported in linq to entities.
                Text = c.Name
            };

Posso comunque riuscirci? Nota che in VB.NET non ci sono problemi con il primo snippet che funziona alla grande, VB è flessibile, non riesco ad abituarmi alla rigidità di C # !!!


2
.ToString () non funziona neanche per LinqToEF in VB. IMHO, un po 'stupido.
StingyJack,

5
@StingyJack, il problema è con ELINQ (entità linq 2), perché traduce il codice in SQL e quando si tratta di una richiesta ToString interna, non sa come tradurre "ToString" in SQL. A differenza degli oggetti linq 2, quando non c'è traduzione e tutto è CLR lambdas, viene eseguito direttamente sugli oggetti richiesti.
Shimmy Weitzhandler,

1
Sono solo irritato dal fatto che consentano di compilare quel tipo di errore e che ho dovuto trollare per sempre per trovare una semplice descrizione inglese della causa (sans legal-ese e academia-ese).
StingyJack,

1
Hai ragione, ma hanno anche ragione, non dovrebbero tradurre in SQL tutte le funzionalità CLR e CLR personalizzate, specialmente non nella primissima versione di EF :) A proposito di ToString, leggi la risposta di Brian: stackoverflow. com / questions / 1066760 /…
Shimmy Weitzhandler,

Fantastico, ma che ne dici delle persone che usano 3.5, no 4? E allora?
Ekaterina,

Risposte:


313

Con EF v4 puoi usare SqlFunctions.StringConvert. Non c'è sovraccarico per int, quindi è necessario eseguire il cast su un doppio o un decimale. Il tuo codice si presenta così:

var items = from c in contacts
            select new ListItem
            {
                Value = SqlFunctions.StringConvert((double)c.ContactId).Trim(),
                Text = c.Name
            };

234
Perché mai non dovrebbero includere un sovraccarico per int?
Jeremy Coenen,

7
@Nestor Questo non funziona per SQL Compact. L'ho scoperto nel modo più duro.
Austin,

24
Per evitare gli spazi bianchi prima del risultato, dovresti usareSqlFunctions.StringConvert((double)c.ContactId).Trim()
Kim Tranjan

2
Sembra non funzionare per SQLite usando System.Data.SQLite Il metodo 'System.String StringConvert (System.Nullable`1 [System.Double])' in Typw 'System.Data.Objects.SqlClient.SqlFunctions' kann nicht in einen Speicherausdruck für "LINQ to Entities" übersetzt werden. (non può essere tradotto in "LINQ to Entities")
OneWorld

5
Risposta eccellente! Nota che, a partire dal fatto che stai usando EF 6, la classe è stata spostata in un altro spazio dei nomi. Quindi, prima di EF 6, è necessario includere: "System.Data.Objects.SqlClient" Se si aggiorna a EF 6 o si sta semplicemente utilizzando questa versione, includere: "System.Data.Entity.SqlServer" Includendo lo spazio dei nomi errato con EF6, il codice verrà compilato correttamente ma genererà un errore di runtime. Spero che questa nota aiuti ad evitare un po 'di confusione.
Leone,

12

Ho risolto un problema simile ponendo la conversione dell'intero in stringa fuori dalla query. Ciò può essere ottenuto inserendo la query in un oggetto.

var items = from c in contacts
            select new 
            {
                Value = c.ContactId,
                Text = c.Name
            };
var itemList = new SelectList();
foreach (var item in items)
{
    itemList.Add(new SelectListItem{ Value = item.ContactId, Text = item.Name });
}

Questo è un modo per risolverlo, ma tieni presente che questo aumenterà il tempo di esecuzione, se hai una grande quantità di oggetti, questa foreach è eccessiva ...
Serlok,

9

Usa LinqToObject: contatti. AsEnumerable ()

var items = from c in contacts.AsEnumerable()
            select new ListItem
            {
                Value = c.ContactId.ToString(),
                Text = c.Name
            };

Grazie. Cordiali saluti, sto cercando di risolvere un problema leggermente diverso. Sto usando LINQ su entity / lambda e questo funziona. Stavo cercando di convertire un Int in String e utilizzare "Contains" per trovare risultati corrispondenti -> ie db.contacts.AsEnumerable (). Where (c => c.ContactId.ToString (). Contains ( searchitem )). ToList (); ;
ejhost il

9
Se chiami AsEnumerablepagherai un prezzo ad alte prestazioni su database più grandi perché porterà tutto in memoria. IEnumerableè più lento rispetto a IQueryableperché il successivo viene eseguito esclusivamente nel database.
CodeArtist,

5

SqlFunctions.StringConvert funzionerà, ma lo trovo ingombrante e, il più delle volte, non ho davvero bisogno di eseguire la conversione di stringhe sul lato SQL.

Quello che faccio se voglio fare manipolazioni di stringhe è innanzitutto eseguire la query in linq-to-entity, quindi manipolare le punture in linq-to-object. In questo esempio, desidero ottenere un set di dati contenente il nome completo di un contatto e ContactLocationKey, che è la concatinazione di stringhe di due colonne di numeri interi (ContactID e LocationID).

// perform the linq-to-entities query, query execution is triggered by ToArray()
var data =
   (from c in Context.Contacts
   select new {
       c.ContactID,
       c.FullName,
       c.LocationID
   }).ToArray();

// at this point, the database has been called and we are working in
// linq-to-objects where ToString() is supported
// Key2 is an extra example that wouldn't work in linq-to-entities
var data2 =
   (from c in data
    select new {
       c.FullName,
       ContactLocationKey = c.ContactID.ToString() + "." + c.LocationID.ToString(),
       Key2 = string.Join(".", c.ContactID.ToString(), c.LocationID.ToString())
    }).ToArray();

Ora, concedo che diventa ingombrante dover scrivere due selezioni anonime, ma direi che è compensato dalla comodità di cui è possibile eseguire funzioni di stringa (e altre) non supportate in L2E. Inoltre, tieni presente che è probabile che ci sia una penalità per le prestazioni usando questo metodo.


4
public static IEnumerable<SelectListItem> GetCustomerList()
        {
            using (SiteDataContext db = new SiteDataContext())
            {
                var list = from l in db.Customers.AsEnumerable()
                           orderby l.CompanyName
                           select new SelectListItem { Value = l.CustomerID.ToString(), Text = l.CompanyName };

                return list.ToList();
            }
        }

L'hai provato e funziona? leggi questa risposta prima.
Shimmy Weitzhandler,

Sì, lo sto già usando. Funziona con MVC3, EF4, CTP5, SQL CE4.
Nestor

Sembra più elegante della boxe per raddoppiare e usare StringConvert.
CmdrTallen,

9
Ma in questo caso recupererai tutti i dati dal database, quindi supponi di voler fare un po 'di filtraggio su questo elenco prima return list.ToList();!!
Wahid Bitar,

4
Quando non puoi accedere a SqlFunctions non hai molte altre opzioni oltre a questa. Tuttavia, avrei usato questo per la mia domanda: return (from l in db.Customers orderby l.CompanyName select new {Id=l.CustomerID, Name=l.CompanyName}).AsEnumerable().Select(c=> new SelectListItem{Value=c.Id.ToString(), Text = c.Name}).ToList();. In questo modo ottiene solo l'ID / nome dal db (anziché tutte le proprietà del cliente) ed esegue l'ordinamento utilizzando l'indice più efficiente sul db.
Brian Cauthon,

3
var selectList = db.NewsClasses.ToList<NewsClass>().Select(a => new SelectListItem({
    Text = a.ClassName,
    Value = a.ClassId.ToString()
});

Innanzitutto, converti in oggetto, quindi toString () sarà corretto.


3

La risposta di Brian Cauthon è eccellente! Solo un piccolo aggiornamento, per EF 6, la classe è stata spostata in un altro spazio dei nomi. Quindi, prima di EF 6, dovresti includere:

System.Data.Objects.SqlClient

Se si aggiorna a EF 6 o si sta semplicemente utilizzando questa versione, includere:

System.Data.Entity.SqlServer

Includendo lo spazio dei nomi errato con EF6, il codice verrà compilato correttamente ma genererà un errore di runtime. Spero che questa nota aiuti ad evitare un po 'di confusione.


Devo dire che anche la tua risposta è eccellente. Ho eseguito l'aggiornamento a EF6 e ho cercato ovunque funzioni SQL. La tua risposta mi ha indicato la giusta direzione. Aggiungo solo che hai bisogno di un riferimento a EntityFramework.SqlServer (potresti avere solo un riferimento a EntityFramework).
Metalogic,

2

Mi sono imbattuto in questo stesso problema quando stavo convertendo la mia app MVC 2 in MVC 3 e solo per dare un'altra soluzione (pulita) a questo problema, voglio pubblicare quello che ho fatto ...

IEnumerable<SelectListItem> producers = new SelectList(Services.GetProducers(),
    "ID", "Name", model.ProducerID);

GetProducers () restituisce semplicemente una raccolta di entità di produttori. PS The SqlFunctions.StringConvert non ha funzionato per me.


2

Se il tuo "contatto" si comporta come un elenco generico, spero che il seguente codice funzioni bene.

var items = contact.Distinct().OrderBy(c => c.Name)
                              .Select( c => new ListItem
                              {
                                Value = c.ContactId.ToString(),
                                Text = c.Name
                              });

Grazie.


2

Un'altra soluzione:

c.ContactId + ""

Basta aggiungere una stringa vuota e verrà convertita in stringa.


Errore restituito: System.NotSupportedException: impossibile eseguire il cast del tipo 'System.Int64' per digitare 'System.Object'. LINQ to Entities supporta solo il cast di tipi di primitiva o enumerazione EDM.
Q Master

1

Usando MySql, SqlFunctions.StringConvertnon ha funzionato per me. Dal momento che utilizzo SelectListItemin più di 20 punti nel mio progetto, ho voluto una soluzione che funzioni senza contendere le oltre 20 dichiarazioni LINQ. La mia soluzione era sottoclasseSelectedListItem per fornire un setter intero, che sposta la conversione del tipo da LINQ. Ovviamente, questa soluzione è difficile da generalizzare, ma è stata molto utile per il mio progetto specifico.

Per utilizzare, creare il seguente tipo e utilizzare nella query LINQ al posto di SelectedListIteme utilizzare IntValue al posto di Valore.

public class BtoSelectedListItem : SelectListItem
{
    public int IntValue
    {
        get { return string.IsNullOrEmpty(Value) ? 0 : int.Parse(Value); }
        set { Value = value.ToString(); }
    }
}

1

se si utilizza il framework di entità e si desidera rendere l'unico int accettabile, è possibile utilizzarlo nella query linq e provare

var items = from c in contacts
        select new ListItem
        {
            Value = (int)ContractId 
            Text = c.Name
        };

funzionerà perché l'utilizzo di (int) trasmetterà il tuo valore a int, quindi non avrai bisogno di alcuna conversione per string in int e otterrai il risultato che desideri.

questo ha funzionato per me nel mio progetto, penso che sarebbe utile per te


-2

La mia comprensione è che devi creare una classe parziale per "estendere" il tuo modello e aggiungere una proprietà di sola lettura che può utilizzare il resto delle proprietà della classe.

public partial class Contact{

   public string ContactIdString
   {
      get{ 
            return this.ContactId.ToString();
      }
   } 
}

Poi

var items = from c in contacts
select new ListItem
{
    Value = c.ContactIdString, 
    Text = c.Name
};

No, non è possibile utilizzare proprietà personalizzate in LINQ to Entities (in .NET 3.5).
Craig Stuntz,

1
Non l'ho provato, ma non funzionerà neanche. poiché non è una proprietà del campo tabella. Potrei prima farlo con ToArray () quindi linqing sugli oggetti ma voglio interrogare il DB. Presumo che non sarà in grado di farlo. Ho creato il mio ListItem che accetta un campo int. Funziona meglio per me.
Shimmy Weitzhandler,

-2
var items = from c in contacts
select new ListItem
{
    Value = String.Concat(c.ContactId), //This Works in Linq to Entity!
    Text = c.Name
};

Ho scoperto che SqlFunctions.StringConvert((double)c.Age)non ha funzionato per me o il campo è di tipoNullable<Int32>

Mi ha richiesto molte ricerche negli ultimi giorni di tentativi ed errori per trovarlo.

Spero che questo aiuti alcuni programmatori là fuori.


1
Non funziona per me. Genera l'eccezione " ... System.String Concat(System.Object)non può essere tradotto in un'espressione negozio ... ".
Slauma,

1
Neanche per me funziona. Ottengo anche "System.NotSupportedException: LINQ to Entities non riconosce il metodo" System.String Concat (System.Object) "e questo metodo non può essere tradotto in un'espressione di archivio."
Camainc,

1
NON FUNZIONA - DEVIA QUESTA RISPOSTA [NotSupportedException: LINQ to Entities non riconosce il metodo "System.String Concat (System.Object)" e questo metodo non può essere tradotto in un'espressione di negozio.]
Philipp Munin,

-6

Puoi provare:

var items = from c in contacts
        select new ListItem
        {
            Value = Convert.ToString(c.ContactId), 
            Text = c.Name
        };

Il codice sopra non funzionerà in quanto genererà un errore che dice "LINQ to Entities non riconosce il metodo" System.String ToString (Int32) "e questo metodo non può essere tradotto in un'espressione store."
GK,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.