Problem beim Konvertieren von int in string in Linq in Entitäten

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

Kann ich das trotzdem erreichen? Beachten Sie, dass es in VB.NET kein Problem gibt, das erste Snippet zu verwenden. Es funktioniert einfach großartig. VB ist flexibel und kann sich nicht an die Strenge von C # gewöhnen !!!

Shimmy Weitzhandler
quelle
2
.ToString () funktioniert auch nicht für LinqToEF in VB. IMHO, irgendwie dumm.
StingyJack
5
@StingyJack, das Problem liegt bei ELINQ (linq 2-Entitäten), da es Ihren Code in SQL übersetzt und bei einer inneren ToString-Anforderung nicht weiß, wie 'ToString' in SQL übersetzt werden soll. Anders als bei Linq 2-Objekten wird, wenn keine Übersetzung vorhanden ist und alles CLR-Lambdas sind, diese direkt für die angeforderten Objekte ausgeführt.
Shimmy Weitzhandler
1
Ich bin nur irritiert darüber, dass sie es erlauben, diese Art von Fehler zu kompilieren, und dass ich für immer trollen musste, um eine einfache englische Beschreibung der Ursache zu finden (ohne Recht und Wissenschaft).
StingyJack
1
Sie haben Recht, aber sie haben auch Recht, sie sollen nicht alle CLR- und angepassten CLR-Funktionen in SQL übersetzen, insbesondere nicht in der sehr frühen Version von EF :) Lesen Sie zum ToString Brians Antwort: Stackoverflow. com / Fragen / 1066760 /…
Shimmy Weitzhandler
Großartig, aber wie wäre es mit Leuten, die 3.5, no 4 verwenden? Dann was?
Ekaterina

Antworten:

312

Mit EF v4 können Sie verwenden SqlFunctions.StringConvert. Es gibt keine Überladung für int, daher müssen Sie in ein Doppel oder eine Dezimalzahl umwandeln. Ihr Code sieht am Ende folgendermaßen aus:

var items = from c in contacts
            select new ListItem
            {
                Value = SqlFunctions.StringConvert((double)c.ContactId).Trim(),
                Text = c.Name
            };
Brian Cauthon
quelle
234
Warum um alles in der Welt würden sie keine Überladung für int beinhalten?
Jeremy Coenen
7
@Nestor Dies funktioniert nicht für SQL Compact. Fand das auf die harte Tour heraus.
Austin
24
Um die Leerzeichen vor dem Ergebnis zu vermeiden, sollten SieSqlFunctions.StringConvert((double)c.ContactId).Trim()
Kim Tranjan
2
Scheint für SQLite mit System.Data.SQLite nicht zu funktionieren. Die Methode 'System.String StringConvert (System.Nullable`1 [System.Double])' in Typw 'System.Data.Objects.SqlClient.SqlFunctions' kann nicht in einem Speicherausdruck für 'LINQ to Entities' werden werden. (kann nicht in "LINQ to Entities" übersetzt werden)
OneWorld
5
Hervorragende Antwort! Bitte beachten Sie, dass ab der Verwendung von EF 6 die Klasse in einen anderen Namespace verschoben wurde. Vor EF 6 sollten Sie also Folgendes einschließen: "System.Data.Objects.SqlClient" Wenn Sie auf EF 6 aktualisieren oder einfach diese Version verwenden, geben Sie Folgendes an: "System.Data.Entity.SqlServer" Durch Einfügen des falschen Namespace in EF6, der Code wird gut kompiliert, aber einen Laufzeitfehler auslösen. Ich hoffe, dieser Hinweis hilft, Verwirrung zu vermeiden.
Leo
12

Ich habe ein ähnliches Problem gelöst, indem ich die Konvertierung der Ganzzahl in eine Zeichenfolge aus der Abfrage entfernt habe. Dies kann erreicht werden, indem die Abfrage in ein Objekt eingefügt wird.

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 });
}
Jente Rosseel
quelle
Dies ist eine Möglichkeit, es zu lösen, aber denken Sie daran, dass dies die Ausführungszeit verlängert. Wenn Sie eine große Anzahl von Objekten haben, ist dieser Foreach übertrieben ...
Serlok
9

Verwenden Sie LinqToObject: Kontakte. AsEnumerable ()

var items = from c in contacts.AsEnumerable()
            select new ListItem
            {
                Value = c.ContactId.ToString(),
                Text = c.Name
            };
Mohammadreza
quelle
Vielen Dank. Zu Ihrer Information, ich versuche ein etwas anderes Problem zu lösen. Ich benutze LINQ für Entities / Lambda und das funktioniert. Ich habe versucht, ein Int in einen String zu konvertieren und mit "Contains" übereinstimmende Ergebnisse zu finden -> dh db.contacts.AsEnumerable (). Where (c => c.ContactId.ToString (). Contains ( searchitem )). ToList (); ;;
Ejhost
9
Wenn Sie anrufen AsEnumerable, zahlen Sie für größere Datenbanken einen hohen Leistungspreis, da dadurch alles gespeichert wird. IEnumerableist langsamer im Vergleich zu, IQueryableweil letzteres ausschließlich in der Datenbank ausgeführt wird.
CodeArtist
5

SqlFunctions.StringConvert wird funktionieren, aber ich finde es umständlich, und die meiste Zeit muss ich die Zeichenfolgenkonvertierung auf der SQL-Seite nicht wirklich durchführen.

Wenn ich Zeichenfolgenmanipulationen durchführen möchte, führe ich zuerst die Abfrage in Linq-to-Entities aus und dann die Stings in Linq-to-Objects. In diesem Beispiel möchte ich einen Datensatz erhalten, der den vollständigen Namen eines Kontakts und ContactLocationKey enthält. Hierbei handelt es sich um die Zeichenfolgenverkettung zweier ganzzahliger Spalten (ContactID und 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();

Nun, ich gebe zu, dass es umständlich wird, zwei anonyme Auswahlen schreiben zu müssen, aber ich würde argumentieren, dass die Bequemlichkeit, mit der Sie Zeichenfolgenfunktionen (und andere) ausführen können, die in L2E nicht unterstützt werden, aufgewogen wird. Denken Sie auch daran, dass es bei dieser Methode wahrscheinlich zu Leistungseinbußen kommt.

Walter Stabosz
quelle
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();
            }
        }
Nestor
quelle
Hast du es getestet und es funktioniert? Lesen Sie diese Antwort vorher.
Shimmy Weitzhandler
Ja, ich benutze es schon. Es funktioniert für MVC3, EF4, CTP5, SQL CE4.
Nestor
Dies scheint eleganter zu sein als das Boxen zu verdoppeln und den StringConvert zu verwenden.
CmdrTallen
9
In diesem Fall rufen Sie jedoch alle Daten aus der Datenbank ab und nehmen an, dass Sie zuvor eine Filterung für diese Liste vornehmen return list.ToList();möchten.
Wahid Bitar
4
Wenn Sie nicht auf SqlFunctions zugreifen können, haben Sie nicht viele andere Optionen als diese. Ich hätte dies jedoch für meine Abfrage verwendet : 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();. Auf diese Weise wird nur die ID / der Name von der Datenbank abgerufen (anstelle aller Kundeneigenschaften) und die Sortierung unter Verwendung des effizienteren Index für die Datenbank durchgeführt.
Brian Cauthon
3
var selectList = db.NewsClasses.ToList<NewsClass>().Select(a => new SelectListItem({
    Text = a.ClassName,
    Value = a.ClassId.ToString()
});

Zuerst in Objekt konvertieren, dann ist toString () korrekt.

Phil Hong
quelle
3

Brian Cauthons Antwort ist ausgezeichnet! Nur ein kleines Update, für EF 6 wurde die Klasse in einen anderen Namespace verschoben. Vor EF 6 sollten Sie also Folgendes einschließen:

System.Data.Objects.SqlClient

Wenn Sie auf EF 6 aktualisieren oder einfach diese Version verwenden, umfassen Sie:

System.Data.Entity.SqlServer

Durch das Einfügen des falschen Namespace in EF6 wird der Code problemlos kompiliert, es wird jedoch ein Laufzeitfehler ausgegeben. Ich hoffe, dieser Hinweis hilft, Verwirrung zu vermeiden.

Löwe
quelle
Ich muss sagen, dass auch Ihre Antwort hervorragend ist. Ich habe ein Upgrade auf EF6 durchgeführt und überall nach SqlFunctions gesucht. Ihre Antwort hat mich in die richtige Richtung gelenkt. Ich füge nur hinzu, dass Sie auch einen Verweis auf EntityFramework.SqlServer benötigen (möglicherweise haben Sie nur einen Verweis auf EntityFramework).
Metalogic
2

Ich bin auf dasselbe Problem gestoßen, als ich meine MVC 2-App auf MVC 3 konvertiert habe. Um eine andere (saubere) Lösung für dieses Problem zu finden, möchte ich veröffentlichen, was ich getan habe ...

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

GetProducers () gibt einfach eine Entitätssammlung von Produzenten zurück. PS Die SqlFunctions.StringConvert hat bei mir nicht funktioniert.

BarryC
quelle
2

Wenn Ihr "Kontakt" als generische Liste fungiert, hoffe ich, dass der folgende Code gut funktioniert.

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

Vielen Dank.

Nawaz
quelle
2

Noch eine Lösung:

c.ContactId + ""

Fügen Sie einfach eine leere Zeichenfolge hinzu und diese wird in eine Zeichenfolge konvertiert.

Igor Valikovsky
quelle
Zurückgegebener Fehler: System.NotSupportedException: Der Typ 'System.Int64' kann nicht in den Typ 'System.Object' umgewandelt werden. LINQ to Entities unterstützt nur das Umwandeln von EDM-Grundelementen oder Aufzählungstypen.
QMaster
1

Mit MySql hat das SqlFunctions.StringConvertbei mir nicht funktioniert. Da ich SelectListItemin meinem Projekt mehr als 20 Stellen verwende, wollte ich eine Lösung, die funktioniert, ohne die über 20 LINQ-Anweisungen zu verzerren. Meine Lösung bestand darin, eine Unterklasse SelectedListItemzu erstellen, um einen Integer-Setter bereitzustellen, der die Typkonvertierung von LINQ wegbewegt. Natürlich ist diese Lösung schwer zu verallgemeinern, war aber für mein spezifisches Projekt sehr hilfreich.

Erstellen Sie zur Verwendung den folgenden Typ und verwenden Sie ihn in Ihrer LINQ-Abfrage anstelle von SelectedListItemund verwenden Sie IntValue anstelle von Value.

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

Wenn Sie das Entity Framework verwenden und das einzige int akzeptabel machen möchten, können Sie dies in der Linq-Abfrage verwenden. Sie können dies versuchen

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

Dies funktioniert, da die Verwendung von (int) Ihren Wert in int umwandelt, sodass Sie keine Konvertierung für Zeichenfolge in int benötigen und das gewünschte Ergebnis erhalten.

Das hat bei mir in meinem Projekt funktioniert. Ich denke, es wäre hilfreich für Sie

Saurabh Solanki
quelle
-2

Nach meinem Verständnis müssen Sie eine Teilklasse erstellen, um Ihr Modell zu "erweitern" und eine schreibgeschützte Eigenschaft hinzuzufügen, die die restlichen Eigenschaften der Klasse nutzen kann.

public partial class Contact{

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

Dann

var items = from c in contacts
select new ListItem
{
    Value = c.ContactIdString, 
    Text = c.Name
};
Mcbeev
quelle
Nein, Sie können keine benutzerdefinierten Eigenschaften in LINQ to Entities (in .NET 3.5) verwenden.
Craig Stuntz
1
Ich habe es nicht getestet, aber es wird auch nicht funktionieren. da es keine Tabellenfeldeigenschaft ist. Ich könnte es zuerst mit ToArray () machen und dann über Objekte linqen, aber ich möchte die DB abfragen. Ich gehe davon aus, dass ich das nicht kann. Ich habe mein eigenes ListItem erstellt, das ein int-Feld enthält. Das funktioniert bei mir besser.
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
};

Ich habe festgestellt, dass SqlFunctions.StringConvert((double)c.Age)das bei mir auch nicht funktioniert hat. Das Feld ist vom TypNullable<Int32>

Ich habe in den letzten Tagen viel versucht, um dies zu finden.

Ich hoffe, das hilft ein paar Programmierern da draußen.

Ken Blackford
quelle
1
Funktioniert bei mir nicht Es wird die Ausnahme " ... System.String Concat(System.Object)kann nicht in einen Geschäftsausdruck übersetzt werden ... " ausgelöst .
Slauma
1
Funktioniert auch bei mir nicht. Ich erhalte außerdem die Meldung "System.NotSupportedException: LINQ to Entities erkennt die Methode 'System.String Concat (System.Object)' nicht und diese Methode kann nicht in einen Geschäftsausdruck übersetzt werden."
Camainc
1
FUNKTIONIERT NICHT - ENTWICKELN SIE DIESE ANTWORT [NotSupportedException: LINQ to Entities erkennt die Methode 'System.String Concat (System.Object)' nicht und diese Methode kann nicht in einen Geschäftsausdruck übersetzt werden.]
Philipp Munin
-6

Kannst du es versuchen:

var items = from c in contacts
        select new ListItem
        {
            Value = Convert.ToString(c.ContactId), 
            Text = c.Name
        };
Tony Heupel
quelle
Der obige Code funktioniert nicht, da der Fehler "LINQ to Entities erkennt die Methode 'System.String ToString (Int32)' nicht erkennt und diese Methode nicht in einen Speicherausdruck übersetzt werden kann."
GK