Проблема з перетворенням 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. ІМХО, вид дурний.
StingyJack

5
@StingyJack, проблема полягає у ELINQ (linq 2 сутності), оскільки він переводить ваш код у SQL, а коли мова заходить про внутрішній запит ToString, він не знає, як перекласти 'ToString' у SQL. На відміну від об'єктів linq 2, коли перекладу немає, і все є лямбдами CLR, він виконується безпосередньо на запитуваних об'єктах.
Шиммі Вайцхандлер

1
Мене просто роздратовує те, що вони дозволяють скласти таку помилку і що мені довелося вічно троліти, щоб знайти простий англійський опис причини (sans legal-ese та academia-ese).
StingyJack

1
Ви маєте рацію, але вони також мають рацію, вони не повинні переводити всі CLR та спеціалізовані функції CLR в SQL, особливо не в самій ранній версії EF :) Про ToString прочитайте відповідь Брайана: stackoverflow. com / questions / 1066760 /…
Shimmy Weitzhandler

Чудово, але як щодо людей, які використовують 3,5, не 4? Тоді що?
Катерина

Відповіді:


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
Чому на землі вони не включають перевантаження для int?
Джеремі Коен

7
@Nestor Це не працює для SQL Compact. Виявив це важким шляхом.
Остін

24
Щоб уникнути пробілів перед результатом, вам слід скористатисяSqlFunctions.StringConvert((double)c.ContactId).Trim()
Кім Тренджан

2
Здається, не працює для SQLite за допомогою System.Data.SQLite Метод "System.String StringConvert (System.Nullable` [[System.Double])" в типі "System.Data.Objects.SqlClient.SqlFunctions" не може бути використаний в Speinherausdruck für 'LINQ для юридичних осіб' übersetzt werden. (не можна перекласти на "LINQ для сутностей")
OneWorld

5
Відмінна відповідь! Зауважте лише, що, починаючи з використання EF 6, клас перемістився в іншу область імен. Отже, перед EF 6 слід включити: "System.Data.Objects.SqlClient" Якщо ви оновите до EF 6 або просто використовуєте цю версію, включіть: "System.Data.Entity.SqlServer", включивши невірну область імен з EF6, код буде складатись чудово, але призведе до помилки виконання. Я сподіваюся, що ця записка допомагає уникнути певної плутанини.
Лев

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

Це один із способів вирішити це, але майте на увазі, що це збільшить час виконання, якщо у вас є велика кількість об'єктів, цей передбачення є надмірним ...
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 (). Where (c => c.ContactId.ToString (). Містить ( searchitem )). ToList (); ;
ejhost

9
Якщо ви зателефонуєте, AsEnumerableви заплатите високу ціну на більшій базі даних, оскільки це принесе все в пам'ять. IEnumerableповільніше порівняно з IQueryableтим, що пізніше виконується виключно в базі даних.
CodeArtist

5

SqlFunctions.StringConvert буде працювати, але я вважаю, що це громіздко, і в більшості випадків у мене немає реальної потреби в перетворенні рядків на стороні SQL.

Що я роблю, якщо хочу зробити маніпуляції з рядком - це спочатку виконати запит у linq-to-subjekt, а потім маніпулювати струнами в linq-to-objects. У цьому прикладі я хочу отримати набір даних, що містить повне ім’я контакту та ContactLocationKey, що є строковим континуацією двох стовпців Integer (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();
            }
        }

Ви перевірили це, і він працює? прочитайте цю відповідь раніше.
Шиммі Вайцхандлер

Так, я вже використовую його. Він працює для MVC3, EF4, CTP5, SQL CE4.
Нестор

Це здається більш елегантним, ніж бокс для подвійного використання та використання StringConvert.
CmdrTallen

9
Але в цьому випадку ви отримаєте всі дані з бази даних, тоді припустимо, що ви хочете зробити деяку фільтрацію в цьому списку раніше return list.ToList();!!
Вахід Бітар

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 / name виходить з db (замість усіх властивостей клієнта) і робить сортування, використовуючи більш ефективний індекс на db.
Брайан Каутон

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

По-перше, перетворіть в об'єкт, тоді toString () буде правильним.


3

Відповідь Брайана Каутона відмінна! Трохи оновлення, для 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 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 для сутностей підтримує лише кастинг примітивних або перелічувальних типів EDM.
QMaster

1

Використовуючи MySql, SqlFunctions.StringConvertмені не вийшло. Оскільки я використовую SelectListItemу своєму проекті більше 20 місць, я хотів вирішити цю проблему, не змінюючи висловлювань 20+ LINQ. Моє рішення полягало в підкласі SelectedListItem, щоб забезпечити цілий сеттер, який відсуває перетворення типу від LINQ. Очевидно, що це рішення важко узагальнити, але було дуже корисним для мого конкретного проекту.

Для використання створіть такий тип і використовуйте у своєму запиті LINQ замість SelectedListItemі використовуйте IntValue замість Value.

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).
Craig Stuntz

1
Я його не тестував, але він також не буде працювати. оскільки це не властивість поля таблиці. Я спершу міг би зробити це за допомогою ToArray (), потім пов'язуючи об'єкти, але я хочу запитати БД. Я припускаю, що не зможе це зробити. Я створив власний ListItem, який займає поле int. Це працює для мене краще.
Шиммі Вайцхандлер

-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)не може бути переведений у вираз магазину ... ".
Слаума

1
Не працює і для мене. Я також отримую "System.NotSupportedException: LINQ до Entities не розпізнає метод" System.String Concat (System.Object) ", і цей метод не може бути переведений у вираз зберігання."
camainc

1
НЕ ПРАЦЮЄ - РОЗРОБИТИ ЦЕ ВІДПОВІДЬ [NotSupportedException: LINQ для 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 для сутностей не розпізнає метод" System.String ToString (Int32) ", і цей метод не може бути переведений у вираз магазину."
GK
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.