Masalah dengan mengubah int ke string di Linq ke entitas

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

Apakah ada cara saya dapat mencapai ini? Catatan, bahwa dalam VB.NET tidak ada masalah menggunakan cuplikan pertama ini berfungsi dengan baik, VB fleksibel, saya tidak dapat terbiasa dengan kekakuan C # !!!

Shimmy Weitzhandler
sumber
2
.ToString () tidak berfungsi untuk LinqToEF di VB juga. IMHO, Agak bodoh.
StingyJack
5
@ StingyJack, masalahnya adalah dengan ELINQ (entitas LINQ 2), karena menerjemahkan kode Anda ke SQL, dan ketika datang ke permintaan ToString batin, ia tidak tahu bagaimana menerjemahkan 'ToString' ke SQL. Berbeda dengan objek linq 2, ketika tidak ada terjemahan, dan semuanya adalah CLR lambdas, maka itu dilakukan langsung pada objek yang diminta.
Shimmy Weitzhandler
1
Saya hanya kesal karena mereka membiarkan kesalahan semacam itu untuk dikompilasi, dan bahwa saya harus troll selamanya untuk menemukan deskripsi bahasa Inggris yang jelas tentang penyebabnya (sans legal-ese dan academia-ese).
StingyJack
1
Anda benar, tetapi mereka juga benar, mereka tidak seharusnya menerjemahkan semua CLR dan fungsionalitas CLR yang dikustomisasi ke dalam SQL, terutama tidak dalam versi awal EF :) Tentang ToString, baca jawaban Brian: stackoverflow. com / pertanyaan / 1066760 / ...
Shimmy Weitzhandler
Hebat, tapi bagaimana dengan orang yang menggunakan 3.5, no 4? Lalu apa?
Ekaterina

Jawaban:

313

Dengan EF v4 Anda dapat menggunakan SqlFunctions.StringConvert. Tidak ada kelebihan untuk int, jadi Anda harus menggunakan ganda atau desimal. Kode Anda akhirnya terlihat seperti ini:

var items = from c in contacts
            select new ListItem
            {
                Value = SqlFunctions.StringConvert((double)c.ContactId).Trim(),
                Text = c.Name
            };
Brian Cauthon
sumber
234
Kenapa mereka tidak memasukkan terlalu banyak untuk int?
Jeremy Coenen
7
@ Nestor Ini tidak berfungsi untuk SQL Compact. Menemukannya dengan cara yang sulit.
Austin
24
Untuk menghindari spasi putih sebelum hasilnya, Anda harus menggunakanSqlFunctions.StringConvert((double)c.ContactId).Trim()
Kim Tranjan
2
Tampaknya tidak berfungsi untuk SQLite menggunakan System.Data.SQLite Methode 'System.String StringConvert (System.Nullable`1 [System.Double])' di Typw 'System.Data.Objects.SqlClient.SqlFungsi' kann nicht di einen Speicherausdruck untuk 'LINQ to Entities' übersetzt werden. (tidak dapat diterjemahkan ke "LINQ ke Entitas")
OneWorld
5
Jawaban yang sangat bagus! Harap dicatat, mulai dari Anda menggunakan EF 6, kelas dipindahkan ke namespace lain. Jadi, sebelum EF 6, Anda harus memasukkan: "System.Data.Objects.SqlClient" Jika Anda memperbarui ke EF 6, atau hanya menggunakan versi ini, sertakan: "System.Data.Entity.SqlServer" Dengan memasukkan namespace yang salah dengan EF6, kode akan dikompilasi dengan baik tetapi akan menyebabkan kesalahan runtime. Saya harap catatan ini membantu menghindari kebingungan.
Leo
12

Saya memecahkan masalah yang sama dengan menempatkan konversi integer ke string dari kueri. Ini dapat dicapai dengan menempatkan kueri ke dalam objek.

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
sumber
Ini adalah salah satu cara untuk menyelesaikannya, tetapi perlu diingat bahwa ini akan meningkatkan waktu eksekusi, jika Anda memiliki sejumlah besar objek, foreach ini berlebihan ...
Serlok
9

Gunakan LinqToObject: kontak. AsEnumerable ()

var items = from c in contacts.AsEnumerable()
            select new ListItem
            {
                Value = c.ContactId.ToString(),
                Text = c.Name
            };
Mohammadreza
sumber
Terima kasih. FYI, saya mencoba menyelesaikan masalah yang sedikit berbeda. Saya menggunakan LINQ untuk entitas / lambda dan ini berfungsi. Saya mencoba untuk mengkonversi Int ke String dan menggunakan "Berisi" untuk menemukan hasil yang cocok -> yaitu db.contacts.AsEnumerable (). Di mana (c => c.ContactId.ToString (). Berisi ( searchitem )). Daftar (); ;
ejhost
9
Jika Anda menelepon, AsEnumerableAnda akan membayar harga kinerja tinggi pada database yang lebih besar karena itu akan membawa semuanya dalam memori. IEnumerablelebih lambat dibandingkan dengan IQueryablekarena nanti dieksekusi secara eksklusif dalam database.
CodeArtist
5

SqlFunctions.StringConvert akan berfungsi, tetapi saya merasa rumit, dan sebagian besar waktu, saya tidak memiliki kebutuhan nyata untuk melakukan konversi string di sisi SQL.

Apa yang saya lakukan jika saya ingin melakukan manipulasi string adalah melakukan kueri di linq-to-entitas terlebih dahulu, kemudian memanipulasi sengatan di linq-to-object. Dalam contoh ini, saya ingin mendapatkan satu set data yang berisi nama lengkap kontak, dan ContactLocationKey, yang merupakan rangkaian string dari dua kolom Integer (ContactID dan 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();

Sekarang, saya yakin bahwa itu tidak praktis untuk harus menulis dua pilihan anonim, tetapi saya berpendapat bahwa ini sebanding dengan kenyamanan di mana Anda dapat melakukan fungsi string (dan lainnya) yang tidak didukung di L2E. Juga perlu diingat bahwa mungkin ada penalti kinerja menggunakan metode ini.

Walter Stabosz
sumber
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
sumber
Apakah Anda mengujinya dan berhasil? baca jawaban ini sebelumnya.
Shimmy Weitzhandler
Ya, saya sudah menggunakannya. Ini berfungsi untuk MVC3, EF4, CTP5, SQL CE4.
Nestor
Ini tampaknya lebih elegan daripada tinju untuk menggandakan dan menggunakan StringConvert.
CmdrTallen
9
Tetapi dalam hal ini Anda akan mengambil semua data dari basis data lalu anggaplah Anda ingin membuat beberapa penyaringan pada daftar ini sebelumnya return list.ToList();!!
Wahid Bitar
4
Ketika Anda tidak dapat mengakses SqlFunctions Anda tidak memiliki banyak pilihan selain ini. Namun, saya akan menggunakan ini untuk pertanyaan saya: 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();. Melakukannya dengan cara ini hanya mendapatkan id / nama dari db (bukan semua properti pelanggan) dan melakukan pengurutan menggunakan indeks yang lebih efisien pada db.
Brian Cauthon
3
var selectList = db.NewsClasses.ToList<NewsClass>().Select(a => new SelectListItem({
    Text = a.ClassName,
    Value = a.ClassId.ToString()
});

Pertama, konversikan ke objek, kemudian toString () akan benar.

phil hong
sumber
3

Jawaban Brian Cauthon luar biasa! Hanya sedikit pembaruan, untuk EF 6, kelas dipindahkan ke namespace lain. Jadi, sebelum EF 6, Anda harus memasukkan:

System.Data.Objects.SqlClient

Jika Anda memperbarui ke EF 6, atau hanya menggunakan versi ini, sertakan:

System.Data.Entity.SqlServer

Dengan memasukkan namespace yang salah dengan EF6, kode akan dikompilasi dengan baik tetapi akan menimbulkan kesalahan runtime. Saya harap catatan ini membantu menghindari kebingungan.

Leo
sumber
Saya harus mengatakan bahwa jawaban Anda sangat baik juga. Saya meningkatkan ke EF6 dan telah mencari di mana-mana untuk SqlFunctions. Jawaban Anda mengarahkan saya ke arah yang benar. Saya hanya akan menambahkan bahwa Anda memerlukan referensi untuk EntityFramework.SqlServer juga (Anda mungkin hanya memiliki referensi ke EntityFramework).
Metalogic
2

Saya mengalami masalah yang sama ketika saya mengubah aplikasi MVC 2 saya ke MVC 3 dan hanya untuk memberikan solusi (bersih) lain untuk masalah ini saya ingin memposting apa yang saya lakukan ...

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

GetProducers () hanya mengembalikan koleksi entitas Producers. PS The SqlFunctions.StringConvert tidak bekerja untuk saya.

BarryC
sumber
2

Jika "kontak" Anda berfungsi sebagai daftar umum, saya harap kode berikut berfungsi dengan baik.

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

Terima kasih.

Nawaz
sumber
2

Satu lagi solusi:

c.ContactId + ""

Cukup tambahkan string kosong dan itu akan dikonversi ke string.

Igor Valikovsky
sumber
Returned Error: System.NotSupportedException: Tidak dapat menggunakan tipe 'System.Int64' untuk mengetik 'System.Object'. LINQ to Entities hanya mendukung casting tipe primitif atau enumerasi EDM.
QMaster
1

Menggunakan MySql, SqlFunctions.StringConvertitu tidak berhasil untuk saya. Karena saya gunakan SelectListItemdi 20+ tempat di proyek saya, saya menginginkan solusi yang berfungsi tanpa memutarbalikkan 20+ pernyataan LINQ. Solusi saya adalah untuk sub-kelasSelectedListItem untuk menyediakan integer setter, yang memindahkan konversi tipe dari LINQ. Jelas, solusi ini sulit untuk digeneralisasi, tetapi cukup membantu untuk proyek spesifik saya.

Untuk menggunakan, buat tipe berikut dan gunakan dalam kueri LINQ Anda di tempat SelectedListItemdan gunakan IntValue sebagai pengganti Value.

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

Jika Anda menggunakan kerangka entitas dan Anda ingin membuat int hanya dapat diterima maka Anda dapat menggunakan ini dalam permintaan LINQ Anda dapat mencoba ini

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

ini akan berfungsi karena menggunakan (int) akan memberikan nilai Anda ke int sehingga Anda tidak perlu konversi untuk string ke int dan Anda mendapatkan hasil yang Anda inginkan.

ini bekerja untuk saya dalam proyek saya, saya pikir ini akan membantu Anda

Saurabh Solanki
sumber
-2

Pemahaman saya adalah bahwa Anda harus membuat kelas parsial untuk "memperluas" model Anda dan menambahkan properti yang hanya bisa dibaca yang dapat memanfaatkan sisa properti kelas.

public partial class Contact{

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

Kemudian

var items = from c in contacts
select new ListItem
{
    Value = c.ContactIdString, 
    Text = c.Name
};
Mcbeev
sumber
Tidak, Anda tidak bisa menggunakan properti kustom di LINQ ke Entitas (dalam. NET 3.5).
Craig Stuntz
1
Saya tidak mengujinya, tetapi tidak akan berhasil. karena ini bukan properti bidang tabel. Pertama-tama saya bisa melakukannya dengan ToArray () kemudian melapisi objek tapi saya ingin query DB. Saya berasumsi tidak akan bisa melakukannya. Saya membuat ListItem saya sendiri yang mengambil bidang int. Itu bekerja lebih baik untuk saya.
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
};

Saya menemukan itu SqlFunctions.StringConvert((double)c.Age) tidak bekerja untuk saya baik bidangnya tipeNullable<Int32>

Butuh banyak pencarian selama beberapa hari terakhir untuk menemukan ini.

Saya harap ini membantu beberapa coders di luar sana.

Ken Blackford
sumber
1
Tidak bekerja untuk saya. Itu melempar pengecualian " ... System.String Concat(System.Object)tidak dapat diterjemahkan ke dalam ekspresi toko ... ".
Slauma
1
Juga tidak bekerja untuk saya. Saya juga mendapatkan "System.NotSupportedException: LINQ to Entities tidak mengenali metode metode 'System.String Concat (System.Object)', dan metode ini tidak dapat diterjemahkan ke dalam ekspresi toko."
camainc
1
JANGAN BEKERJA - MENGEMBANGKAN JAWABAN INI [NotSupportedException: LINQ to Entities tidak mengenali metode metode 'System.Tring Concat (System.Object)', dan metode ini tidak dapat diterjemahkan ke dalam ekspresi toko.]
Philipp Munin
-6

Bisakah kamu mencoba:

var items = from c in contacts
        select new ListItem
        {
            Value = Convert.ToString(c.ContactId), 
            Text = c.Name
        };
Tony Heupel
sumber
Kode di atas tidak akan berfungsi karena akan menimbulkan kesalahan yang mengatakan "LINQ ke Entitas tidak mengenali metode metode 'System.String ToString (Int32)', dan metode ini tidak dapat diterjemahkan ke dalam ekspresi toko."
GK