Vấn đề với việc chuyển đổi int thành chuỗi trong Linq thành các thực thể


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

Có dù sao tôi có thể đạt được điều này? Lưu ý rằng trong VB.NET không có vấn đề gì khi sử dụng đoạn mã đầu tiên, nó hoạt động rất tuyệt, VB rất linh hoạt, tôi không thể làm quen với sự nghiêm ngặt của C # !!!


2
.ToString () cũng không hoạt động cho LinqToEF trong VB. IMHO, Loại ngu ngốc.
StingyJack

5
@StingyJack, vấn đề là ở ELINQ (thực thể linq 2), vì nó dịch mã của bạn sang SQL và khi nói đến yêu cầu ToString bên trong, nó không biết cách dịch 'ToString' sang SQL. Không giống như các đối tượng linq 2, khi không có bản dịch và mọi thứ là CLR lambdas, thì nó được thực hiện trực tiếp trên các đối tượng được yêu cầu.
Shimmy Weitzhandler

1
Tôi chỉ thấy khó chịu khi họ cho phép loại lỗi đó được biên soạn và tôi phải troll mãi mãi để tìm một mô tả tiếng Anh đơn giản về nguyên nhân (sans law-ese và academia-ese).
StingyJack

1
Bạn đúng, nhưng họ cũng đúng, họ không được phép dịch tất cả chức năng CLR và tùy chỉnh CLR sang SQL, đặc biệt là không phải trong phiên bản đầu tiên của EF :) Về ToString, hãy đọc câu trả lời của Brian: stackoverflow. com / câu hỏi / 1066760 / Hoài
Shimmy Weitzhandler

Tuyệt vời, nhưng những người sử dụng 3,5, không 4 thì sao? Rồi sao?
Bibina

Câu trả lời:


313

Với EF v4 bạn có thể sử dụng SqlFunctions.StringConvert. Không có quá tải cho int vì vậy bạn cần phải tăng gấp đôi hoặc thập phân. Mã của bạn kết thúc như thế này:

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

234
Tại sao trên trái đất họ sẽ không bao gồm một quá tải cho int?
Jeremy Coenen

7
@Nestor Điều này không hoạt động cho SQL Compact. Tìm thấy điều đó một cách khó khăn.
Austin

24
Để tránh các khoảng trắng trước kết quả, bạn nên sử dụngSqlFunctions.StringConvert((double)c.ContactId).Trim()
Kim Tranjan

2
Có vẻ như không hoạt động đối với SQLite khi sử dụng System.Data.SQLite Methode 'System.String StringConvert (System.Nullable`1 [System.Double])' trong typw 'System.Data.Objects.SqlClient.SqlFifts' kann nicht in einen Spe Richaus für 'LINQ to Entities' übersetzt werden. (không thể dịch thành "LINQ to Entities")
OneWorld

5
Câu trả lời tuyệt vời! Chỉ xin lưu ý, bắt đầu khi bạn đang sử dụng EF 6, lớp đã được chuyển sang một không gian tên khác. Vì vậy, trước EF 6, bạn nên bao gồm: "System.Data.Objects.SqlClient" Nếu bạn cập nhật lên EF 6, hoặc đơn giản là đang sử dụng phiên bản này, bao gồm: "System.Data.Entity.SqlServer" Bằng cách bao gồm không gian tên không chính xác với EF6, mã sẽ biên dịch tốt nhưng sẽ gây ra lỗi thời gian chạy. Tôi hy vọng lưu ý này sẽ giúp tránh một số nhầm lẫn.
Leo

12

Tôi đã giải quyết một vấn đề tương tự bằng cách đặt chuyển đổi số nguyên thành chuỗi ra khỏi truy vấn. Điều này có thể đạt được bằng cách đặt truy vấn vào một đối tượng.

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

Đây là một cách để giải quyết nó, nhưng hãy nhớ rằng điều này sẽ tăng thời gian thực hiện, nếu bạn có số lượng đối tượng lớn, thì lời nói này là quá mức cần thiết ...
Serlok

9

Sử dụng LinqToObject: danh bạ. Vô số ()

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

Cảm ơn. FYI, tôi đang cố gắng giải quyết một vấn đề hơi khác. Tôi đang sử dụng LINQ cho các thực thể / lambda và điều này hoạt động. Tôi đã cố gắng chuyển đổi một Int thành String và sử dụng "Chứa" để tìm kết quả khớp -> tức là db.contacts.AsEnumerable (). Trong đó (c => c.ContactId.ToString (). Chứa ( searchitem )). (); ;
ejhost

9
Nếu bạn gọi, AsEnumerablebạn sẽ trả giá hiệu năng cao trên cơ sở dữ liệu lớn hơn vì nó sẽ mang lại mọi thứ trong bộ nhớ. IEnumerablechậm hơn so với IQueryablevì sau này được thực hiện riêng trong cơ sở dữ liệu.
CodeArtist

5

SqlFifts.StringConvert sẽ hoạt động, nhưng tôi thấy nó cồng kềnh và hầu hết thời gian, tôi không có nhu cầu thực sự để thực hiện chuyển đổi chuỗi ở phía SQL.

Những gì tôi làm nếu tôi muốn thực hiện các thao tác chuỗi là thực hiện truy vấn trong linq-to-entity trước, sau đó thao tác các stings trong linq-to-object. Trong ví dụ này, tôi muốn có được một tập hợp dữ liệu chứa tên đầy đủ của Liên hệ và ContactLocationKey, đó là cách nối chuỗi của hai cột Số nguyên (ContactID và 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();

Bây giờ, tôi cho rằng sẽ rất khó khăn khi phải viết hai lựa chọn ẩn danh, nhưng tôi cho rằng nó vượt trội hơn bởi sự tiện lợi mà bạn có thể thực hiện các hàm chuỗi (và các hàm khác) không được hỗ trợ trong L2E. Cũng nên nhớ rằng có thể có một hình phạt hiệu suất sử dụng phương pháp này.


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

Bạn đã kiểm tra nó và nó hoạt động? đọc câu trả lời này trước
Shimmy Weitzhandler

Có, tôi đang sử dụng nó. Nó hoạt động cho MVC3, EF4, CTP5, SQL CE4.
Nestor

Điều này có vẻ thanh lịch hơn so với quyền anh để tăng gấp đôi và sử dụng StringConvert.
CmdrTallen

9
Nhưng trong trường hợp này, bạn sẽ lấy tất cả dữ liệu từ cơ sở dữ liệu sau đó giả sử rằng bạn muốn thực hiện một số bộ lọc trong danh sách này trước return list.ToList();!!
Wahid Bitar

4
Khi bạn không thể truy cập SqlFifts, bạn không có nhiều tùy chọn khác ngoài điều này. Tuy nhiên, tôi đã sử dụng điều này cho truy vấn của mình : 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();. Làm theo cách này chỉ nhận được id / name từ db (thay vì tất cả các thuộc tính của khách hàng) và thực hiện sắp xếp bằng cách sử dụng chỉ mục hiệu quả hơn trên db.
Brian Cauthon

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

Đầu tiên, chuyển đổi thành đối tượng, sau đó toString () sẽ chính xác.


3

Câu trả lời của Brian Cauthon là tuyệt vời! Chỉ cần một bản cập nhật nhỏ, đối với EF 6, lớp đã được chuyển sang một không gian tên khác. Vì vậy, trước EF 6, bạn nên bao gồm:

System.Data.Objects.SqlClient

Nếu bạn cập nhật lên EF 6 hoặc đơn giản là đang sử dụng phiên bản này, hãy bao gồm:

System.Data.Entity.SqlServer

Bằng cách bao gồm không gian tên không chính xác với EF6, mã sẽ biên dịch tốt nhưng sẽ gây ra lỗi thời gian chạy. Tôi hy vọng lưu ý này sẽ giúp tránh một số nhầm lẫn.


Tôi phải nói rằng câu trả lời của bạn là tuyệt vời là tốt. Tôi đã nâng cấp lên EF6 và đã tìm kiếm ở khắp mọi nơi cho SqlFifts. Câu trả lời của bạn chỉ cho tôi đi đúng hướng. Tôi sẽ chỉ thêm rằng bạn cần một tham chiếu đến EntityFramework.SqlServer (bạn chỉ có thể có một tham chiếu đến EntityFramework).
Metalogic

2

Tôi gặp vấn đề tương tự khi tôi chuyển đổi ứng dụng MVC 2 của mình sang MVC 3 và chỉ để đưa ra một giải pháp (sạch) khác cho vấn đề này, tôi muốn đăng những gì tôi đã làm ...

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

Get Producers () chỉ đơn giản trả về một bộ sưu tập thực thể của Nhà sản xuất. PS SqlFifts.StringConvert không hoạt động với tôi.


2

Nếu "liên hệ" của bạn hoạt động như một danh sách chung, tôi hy vọng đoạn mã sau hoạt động tốt.

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

Cảm ơn.


2

Thêm một giải pháp:

c.ContactId + ""

Chỉ cần thêm chuỗi rỗng và nó sẽ được chuyển đổi thành chuỗi.


Lỗi trả về: System.NotSupportedException: Không thể truyền loại 'System.Int64' để nhập 'System.Object'. LINQ to Entities chỉ hỗ trợ truyền các kiểu nguyên thủy hoặc liệt kê EDM.
QMaster

1

Sử dụng MySql, SqlFunctions.StringConvertnó không hoạt động với tôi. Vì tôi sử dụng SelectListItemở hơn 20 địa điểm trong dự án của mình, tôi muốn một giải pháp hoạt động mà không làm trái với 20+ câu lệnh LINQ. Giải pháp của tôi là đến lớp họcSelectedListItem để cung cấp một bộ cài đặt số nguyên, giúp chuyển đổi loại chuyển đổi khỏi LINQ. Rõ ràng, giải pháp này rất khó để khái quát, nhưng khá hữu ích cho dự án cụ thể của tôi.

Để sử dụng, hãy tạo loại sau và sử dụng trong truy vấn LINQ của bạn thay cho SelectedListItemvà sử dụng IntValue thay cho Giá trị.

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

1

nếu bạn sử dụng khung thực thể và bạn muốn làm cho int duy nhất được chấp nhận thì bạn có thể sử dụng điều này trong truy vấn linq, bạn có thể thử điều này

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

nó sẽ hoạt động vì sử dụng (int) sẽ chuyển giá trị của bạn sang int để bạn không cần bất kỳ chuyển đổi nào cho chuỗi thành int và bạn nhận được kết quả bạn muốn.

điều này làm việc cho tôi trong dự án của tôi, tôi nghĩ nó sẽ hữu ích cho bạn


-2

Tôi hiểu rằng bạn phải tạo một lớp một phần để "mở rộng" mô hình của bạn và thêm một thuộc tính chỉ đọc có thể sử dụng phần còn lại của các thuộc tính của lớp.

public partial class Contact{

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

Sau đó

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

Không, bạn không thể sử dụng các thuộc tính tùy chỉnh trong LINQ to Entities (trong .NET 3.5).
Craig Stuntz

1
Tôi đã không thử nó, nhưng nó cũng không hoạt động. vì nó không phải là một thuộc tính trường bảng. Trước tiên tôi có thể làm điều đó với ToArray () sau đó lin Khánh trên các đối tượng nhưng tôi muốn truy vấn DB. Tôi cho rằng sẽ không thể làm điều đó. Tôi đã tạo ListItem của riêng mình có một trường int. Điều đó làm việc tốt hơn cho tôi.
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
};

Tôi thấy rằng SqlFunctions.StringConvert((double)c.Age)nó không làm việc cho tôi hoặc lĩnh vực là loạiNullable<Int32>

Đã cho tôi rất nhiều tìm kiếm trong vài ngày qua và thử nghiệm để tìm thấy điều này.

Tôi hy vọng điều này sẽ giúp một vài lập trình viên ngoài kia.


1
Không làm việc cho tôi. Nó ném ngoại lệ " ... System.String Concat(System.Object)không thể dịch thành biểu thức cửa hàng ... ".
Slauma

1
Nó cũng không làm việc cho tôi. Tôi cũng nhận được "System.NotSupportedException: LINQ to Entities không nhận ra phương thức 'System.String Concat (System.Object)' và phương thức này không thể được dịch thành biểu thức lưu trữ."
camainc

1
KHÔNG LÀM VIỆC - Xác định TRẢ LỜI NÀY [Không được hỗ trợ Ngoại lệ: LINQ to Entities không nhận ra phương thức 'System.String Concat (System.Object)' và phương thức này không thể được dịch thành biểu thức lưu trữ.]
Philipp Munin

-6

Bạn có thể thử:

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

Đoạn mã trên sẽ không hoạt động vì nó sẽ báo lỗi "LINQ to Entities không nhận ra phương thức 'System.String ToString (Int32)' và phương thức này không thể được dịch thành biểu thức lưu trữ."
GK
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.