ปัญหาเกี่ยวกับการแปลง int เป็นสตริงใน Linq เป็นเอนทิตี


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

มีอยู่ฉันสามารถบรรลุนี้ โปรดทราบว่าใน VB.NET ไม่มีปัญหาในการใช้ตัวอย่างข้อมูลแรกมันใช้งานได้ดี VB มีความยืดหยุ่นฉันไม่สามารถคุ้นเคยกับความเข้มงวดของ C # !!!


2
.ToString () ไม่ทำงานสำหรับ LinqToEF ใน VB เช่นกัน IMHO คนโง่
StingyJack

5
@StingyJack ปัญหาเกิดขึ้นกับ ELINQ (linq 2 เอนทิตี) เพราะแปลโค้ดของคุณเป็น SQL และเมื่อมันมาถึงคำร้องขอ ToString ภายในก็ไม่รู้วิธีแปล 'ToString' เป็น SQL แตกต่างจากวัตถุ linq 2 เมื่อไม่มีการแปลและทุกอย่างเป็น lambdas CLR ดังนั้นมันจะถูกดำเนินการโดยตรงบนวัตถุที่ร้องขอ
Shimmy Weitzhandler

1
ฉันแค่หงุดหงิดที่พวกเขาอนุญาตให้รวบรวมข้อผิดพลาดชนิดนั้นและฉันต้องหมุนรอบตัวเองตลอดไปเพื่อหาคำอธิบายภาษาอังกฤษที่ชัดเจนเกี่ยวกับสาเหตุ (sans legal-ese และ academia-ese)
StingyJack

1
คุณพูดถูก แต่พวกเขาพูดถูกพวกเขาไม่ควรแปล CLR ทั้งหมดและปรับแต่งฟังก์ชันการทำงานของ CLR ให้เป็น SQL โดยเฉพาะอย่างยิ่งไม่ใช่ในรุ่นแรก ๆ ของ EF :) เกี่ยวกับ ToString อ่านคำตอบของ Brian: stackoverflow com / คำถาม / 1066760 / …
Shimmy Weitzhandler

เยี่ยมมาก แต่แล้วคนที่ใช้ 3.5 ไม่ใช่ 4 ล่ะ? แล้วไง?
Ekaterina

คำตอบ:


313

กับ EF v4 SqlFunctions.StringConvertคุณสามารถใช้ ไม่มีการโอเวอร์โหลดสำหรับ int ดังนั้นคุณจำเป็นต้องแปลงค่าเป็นสองเท่าหรือทศนิยม รหัสของคุณจะมีลักษณะดังนี้:

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

234
ทำไมพวกเขาถึงไม่รวม overload สำหรับ int?
Jeremy Coenen

7
@Nestor วิธีนี้ใช้ไม่ได้กับ SQL Compact พบว่าออกมาลำบาก
Austin

24
เพื่อหลีกเลี่ยงช่องว่างก่อนผลลัพธ์คุณควรใช้SqlFunctions.StringConvert((double)c.ContactId).Trim()
Kim Tranjan

2
ดูเหมือนว่าจะไม่ทำงานสำหรับ SQLite โดยใช้ System.Data.SQLite Methode 'System.String StringConvert (System.Nullable`1 [System.Double])' ใน Typw 'System.Data.Objects.SqlClient.SqlFientions' einen Speicherausdruck ' für 'LINQ to Entities' übersetzt werden (ไม่สามารถแปลเป็น "LINQ ไปยังเอนทิตี")
OneWorld

5
คำตอบที่ยอดเยี่ยม! เพียงแค่โปรดทราบว่าเมื่อคุณเริ่มใช้ EF 6 คลาสก็ถูกย้ายไปที่เนมสเปซอื่น ดังนั้นก่อน EF 6 คุณควรรวม: "System.Data.Objects.SqlClient" หากคุณอัปเดตเป็น EF 6 หรือเพียงใช้รุ่นนี้ให้รวมถึง: "System.Data.Entity.SqlServer" โดยการรวม namespace ที่ไม่ถูกต้องด้วย EF6 รหัสจะคอมไพล์ได้ แต่จะมีข้อผิดพลาด runtime ฉันหวังว่าข้อความนี้ช่วยในการหลีกเลี่ยงความสับสน
Leo

12

ฉันแก้ไขปัญหาที่คล้ายกันโดยวางการแปลงจำนวนเต็มเป็นสายอักขระจากแบบสอบถาม สิ่งนี้สามารถทำได้โดยการใส่แบบสอบถามลงในวัตถุ

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

นี่เป็นวิธีหนึ่งในการแก้ปัญหา แต่โปรดจำไว้ว่าจะเพิ่มเวลาในการดำเนินการถ้าคุณมีวัตถุจำนวนมาก foreach นี้มีขนาดใหญ่เกินไป ...
Serlok

9

ใช้ LinqToObject: ผู้ติดต่อ AsEnumerable ()

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

ขอบคุณ FYI ฉันพยายามแก้ไขปัญหาที่แตกต่างออกไปเล็กน้อย ฉันใช้ LINQ กับเอนทิตี / แลมบ์ดาและใช้งานได้ ฉันพยายามแปลง Int เป็น String และใช้ "มี" เพื่อค้นหาผลลัพธ์ที่ตรงกัน -> เช่น db.contacts.AsEnumerable (). โดยที่ (c => c.ContactId.ToString (). ประกอบด้วย ( searchitem )) ToList (); ;
ejhost

9
ถ้าคุณโทรหาAsEnumerableคุณจะจ่ายราคาประสิทธิภาพสูงในฐานข้อมูลขนาดใหญ่เพราะมันจะนำทุกสิ่งมาไว้ในหน่วยความจำ IEnumerableจะช้ากว่าเมื่อเปรียบเทียบกับIQueryableเพราะในภายหลังจะถูกดำเนินการเฉพาะในฐานข้อมูล
CodeArtist

5

SqlFunctions.StringConvert จะใช้งานได้ แต่ฉันคิดว่ามันยุ่งยากและส่วนใหญ่ฉันไม่จำเป็นต้องทำการแปลงสตริงที่ด้าน SQL

ฉันจะทำอย่างไรถ้าฉันต้องการทำการจัดการสตริงให้ทำเคียวรีใน linq-to-entity ก่อนจากนั้นจัดการ stings ใน linq-to-objects ในตัวอย่างนี้ฉันต้องการได้รับชุดข้อมูลที่มีชื่อเต็มของผู้ติดต่อและ ContactLocationKey ซึ่งเป็นการเชื่อมต่อสายอักขระของคอลัมน์จำนวนเต็มสองคอลัมน์ (ContactID และ 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();

ตอนนี้ฉันอนุญาตให้มันยุ่งยากกว่าที่จะต้องเขียนตัวเลือกนิรนามสองตัว แต่ฉันจะเถียงว่ามันเกินดุลโดยความสะดวกสบายที่คุณสามารถใช้งานฟังก์ชั่นสตริง (และอื่น ๆ ) ที่ไม่ได้รับการสนับสนุนใน L2E โปรดทราบว่าอาจมีการปรับประสิทธิภาพด้วยวิธีนี้


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

คุณทดสอบและใช้งานได้หรือไม่ อ่านคำตอบนี้ก่อน
Shimmy Weitzhandler

ใช่ฉันใช้มันไปแล้ว ใช้งานได้กับ MVC3, EF4, CTP5, SQL CE4
Nestor

ดูเหมือนว่าจะสวยงามกว่าการชกมวยเป็นสองเท่าและใช้ StringConvert
CmdrTallen

9
แต่ในกรณีนี้คุณจะดึงข้อมูลทั้งหมดจากฐานข้อมูลแล้วสมมติว่าคุณต้องการกรองบางอย่างในรายการนี้ก่อนreturn list.ToList();!!
Wahid Bitar

4
เมื่อคุณไม่สามารถเข้าถึง SqlFunctions คุณไม่มีตัวเลือกอื่นอีกมากมายนอกเหนือจากนี้ อย่างไรก็ตามฉันจะใช้สิ่งนี้กับข้อความค้นหาของฉัน: 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();. การทำเช่นนี้จะได้รับ id / ชื่อจาก db (แทนที่จะเป็นคุณสมบัติของลูกค้าทั้งหมด) และทำการเรียงลำดับโดยใช้ดัชนีที่มีประสิทธิภาพมากขึ้นบน db
Brian Cauthon

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

ประการแรกแปลงเป็นวัตถุจากนั้น toString () จะถูกต้อง


3

คำตอบของ Brian Cauthon นั้นยอดเยี่ยมมาก! แค่อัปเดตเล็กน้อยสำหรับ EF 6 คลาสก็ถูกย้ายไปที่เนมสเปซอื่น ดังนั้นก่อน EF 6 คุณควรรวม:

System.Data.Objects.SqlClient

หากคุณอัปเดตเป็น EF 6 หรือเพียงแค่ใช้เวอร์ชันนี้รวมถึง:

System.Data.Entity.SqlServer

โดยการรวมเนมสเปซที่ไม่ถูกต้องกับ EF6 รหัสจะคอมไพล์ได้ดี แต่จะเกิดข้อผิดพลาดขณะทำงาน ฉันหวังว่าข้อความนี้ช่วยในการหลีกเลี่ยงความสับสน


ฉันต้องบอกว่าคำตอบของคุณนั้นยอดเยี่ยมเช่นกัน ฉันอัพเกรดเป็น EF6 และมองหา SqlFunctions ทุกที่ คำตอบของคุณชี้ให้ฉันในทิศทางที่ถูกต้อง ฉันจะเพิ่มว่าคุณต้องมีการอ้างอิงถึง EntityFramework.SqlServer เช่นกัน (คุณอาจมีการอ้างอิงถึง EntityFramework เท่านั้น)
Metalogic

2

ฉันพบปัญหาเดียวกันนี้เมื่อฉันแปลงแอพ MVC 2 ของฉันเป็น MVC 3 และเพียงแค่ให้โซลูชันอื่น (สะอาด) กับปัญหานี้ฉันต้องการโพสต์สิ่งที่ฉันทำ ...

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

GetProducers () เพียงแค่ส่งกลับคอลเลกชันนิติบุคคลของผู้ผลิต PS The SqlFunctions.StringConvert ไม่ได้ผลสำหรับฉัน


2

หาก "ผู้ติดต่อ" ของคุณทำหน้าที่เป็นรายการทั่วไปฉันหวังว่ารหัสต่อไปนี้จะทำงานได้ดี

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

ขอบคุณ


2

ทางออกหนึ่งเพิ่มเติม:

c.ContactId + ""

เพียงแค่เพิ่มสตริงที่ว่างเปล่าและมันจะถูกแปลงเป็นสตริง


ข้อผิดพลาดที่ส่งคืน: System.NotSupportedException: ไม่สามารถส่งประเภท 'System.Int64' เพื่อพิมพ์ 'System.Object' LINQ to Entities รองรับการแคสต์ EDM แบบดั้งเดิมหรือการแจงนับเท่านั้น
QMaster

1

ใช้ MySql สิ่งที่SqlFunctions.StringConvertไม่ได้ผลสำหรับฉัน เนื่องจากฉันใช้งานSelectListItemมากกว่า 20 แห่งในโครงการของฉันฉันต้องการโซลูชันที่ทำงานได้โดยไม่ขัดแย้งกับคำสั่ง LINQ 20+ โซลูชันของฉันคือ sub-class SelectedListItemเพื่อจัดเตรียม setter จำนวนเต็มซึ่งย้ายการแปลงชนิดออกจาก LINQ เห็นได้ชัดว่าวิธีนี้เป็นเรื่องยากที่จะพูดคุย แต่ก็มีประโยชน์มากสำหรับโครงการเฉพาะของฉัน

หากต้องการใช้สร้างประเภทต่อไปนี้และใช้ในคิวรี LINQ ของคุณแทนSelectedListItemและใช้ IntValue แทนค่า

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

1

ถ้าคุณใช้เอนทิตีเฟรมเวิร์กและคุณต้องการทำให้ int เป็นที่ยอมรับเท่านั้นคุณสามารถใช้มันในเคียวรี linq ได้

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

มันจะทำงานได้เพราะการใช้ (int) จะทำให้คุณค่าของคุณเป็น int ดังนั้นคุณไม่จำเป็นต้องแปลงสตริงเป็น int และคุณได้ผลลัพธ์ที่ต้องการ

สิ่งนี้ใช้ได้กับฉันในโครงการของฉันฉันคิดว่ามันจะเป็นประโยชน์สำหรับคุณ


-2

ความเข้าใจของฉันคือคุณต้องสร้างคลาสบางส่วนเพื่อ "ขยาย" โมเดลของคุณและเพิ่มคุณสมบัติที่อ่านได้อย่างเดียวซึ่งสามารถใช้คุณสมบัติที่เหลือของคลาสได้

public partial class Contact{

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

แล้วก็

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

ไม่คุณไม่สามารถใช้คุณสมบัติที่กำหนดเองใน LINQ ไปยังเอนทิตี (ใน. NET 3.5)
เครก Stuntz

1
ฉันไม่ได้ทดสอบ แต่มันก็ไม่ได้ผลเช่นกัน เนื่องจากไม่ใช่คุณสมบัติเขตข้อมูลตาราง ฉันสามารถทำได้ด้วย ToArray () จากนั้น linqing เหนือวัตถุ แต่ฉันต้องการสอบถาม DB ฉันคิดว่าจะไม่สามารถทำได้ ฉันสร้าง ListItem ของตัวเองที่ใช้ฟิลด์ int มันใช้งานได้ดีกว่าสำหรับฉัน
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
};

ฉันพบSqlFunctions.StringConvert((double)c.Age)ว่าไม่ได้ผลสำหรับฉันทั้งฟิลด์เป็นประเภทNullable<Int32>

เอาการค้นหาจำนวนมากในช่วงสองสามวันสุดท้ายของการทดลองและข้อผิดพลาดเพื่อค้นหา

ฉันหวังว่านี่จะช่วยให้ผู้เขียนโค้ดสองสามคนอยู่ที่นั่น


1
ใช้งานไม่ได้สำหรับฉัน มันมีข้อยกเว้น " ... System.String Concat(System.Object)ไม่สามารถแปลเป็นนิพจน์ร้านค้า ... "
Slauma

1
ไม่ได้ผลสำหรับฉันเช่นกัน ฉันยังได้รับ "System.NotSupportedException: LINQ ไปยังเอนทิตีไม่รู้จักเมธอด 'System.String Concat (System.Object)' และวิธีนี้ไม่สามารถแปลเป็นนิพจน์ร้านค้าได้"
camainc

1
ไม่ทำงาน - แก้คำตอบนี้ [NotSupportedException: LINQ to Entities ไม่รู้จักวิธีการ 'System.String Concat (System.Object)' วิธีการและวิธีนี้ไม่สามารถแปลเป็นนิพจน์ร้านค้าได้
Philipp Munin

-6

คุณลองได้ไหม:

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

รหัสด้านบนจะไม่ทำงานเนื่องจากจะมีข้อผิดพลาดแจ้งว่า "LINQ to Entities ไม่รู้จักวิธีการ 'System.String ToString (Int32)' และวิธีนี้ไม่สามารถแปลเป็นนิพจน์ร้านค้าได้"
GK
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.