【问题标题】:Problem with converting int to string in Linq to entities在 Linq 中将 int 转换为字符串到实体的问题
【发布时间】:2010-11-07 04:41:24
【问题描述】:
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 中使用第一个 sn-p 没有问题,它工作得很好,VB 很灵活,我无法习惯 C# 的严格性!!!

【问题讨论】:

  • .ToString() 也不适用于 VB 中的 LinqToEF。恕我直言,有点愚蠢。
  • @StingyJack,问题出在 ELINQ(linq 2 实体),因为它将您的代码转换为 SQL,当涉及到内部 ToString 请求时,它不知道如何翻译 ' ToString' 到 SQL。与 linq 2 对象不同,当没有翻译并且一切都是 CLR lambdas 时,它会直接在请求的对象上执行。
  • 我只是对他们允许编译这种错误感到恼火,而且我不得不永远寻找一个简单的英文描述原因(没有法律和学术界) .
  • 你是对的,但他们也是对的,他们不应该将所有 CLR 和自定义 CLR 功能转换为 SQL,尤其是在早期版本的 EF 中:) ToString,阅读 Brian 的回答:stackoverflow.com/questions/1066760/…
  • 很好,但是使用 3.5 而不是 4 的人呢?然后呢?

标签: c# asp.net linq-to-entities tostring


【解决方案1】:

使用 EF v4,您可以使用 SqlFunctions.StringConvert。 int 没有重载,因此您需要转换为双精度或小数。你的代码最终看起来像这样:

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

【讨论】:

  • 为什么它们不包含 int 的重载?
  • @Nestor 这不适用于 SQL Compact。很难找到。
  • 为了避免结果前的空格,你应该使用SqlFunctions.StringConvert((double)c.ContactId).Trim()
  • 似乎不适用于使用 System.Data.SQLite 的 SQLite Typw 'System.Data.Objects.SqlClient 中的 Methode 'System.String StringConvert(System.Nullable`1[System.Double])' .SqlFunctions' kann nicht 在 einen Speicherausdruck für 'LINQ to Entities' übersetzt werden。 (不能翻译成“LINQ to Entities”)
  • 优秀的答案!请注意,从您使用 EF 6 开始,该类已移至另一个命名空间。因此,在 EF 6 之前,您应该包含:“System.Data.Objects.SqlClient” 如果您更新到 EF 6,或者只是使用此版本,请包含:“System.Data.Entity.SqlServer” 通过包含不正确的命名空间EF6,代码编译得很好,但会引发运行时错误。我希望此说明有助于避免一些混淆。
【解决方案2】:

我通过将整数到字符串的转换排除在查询之外来解决了类似的问题。这可以通过将查询放入对象来实现。

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 是矫枉过正...
【解决方案3】:

使用 LinqToObject : 联系人。AsEnumerable()

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

【讨论】:

  • 谢谢。仅供参考,我正在尝试解决一个稍微不同的问题。我正在使用 LINQ to entity / lambda,这很有效。我试图将 Int 转换为 String 并使用“包含”来查找匹配的结果 --> 即 db.contacts.AsEnumerable().Where(c => c.ContactId.ToString().Contains(searchitem)).ToList(); ;
  • 如果您调用AsEnumerable,您将为大型数据库付出高性能代价,因为它将所有内容都放入内存。 IEnumerableIQueryable 慢,因为后者在数据库中独占执行。
【解决方案4】:

SqlFunctions.StringConvert 可以,但我觉得很麻烦,而且大多数时候,我并没有真正需要在 SQL 端执行字符串转换。

如果我想做字符串操作,我会先在 linq-to-entities 中执行查询,然后在 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 不支持的字符串(和其他)函数的便利性要重要。另请注意,使用此方法可能会降低性能。

【讨论】:

    【解决方案5】:
    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();
                }
            }
    

    【讨论】:

    • 你测试过它并且它有效吗?阅读this之前的答案。
    • 是的,我已经在使用它了。它适用于 MVC3、EF4、CTP5、SQL CE4。
    • 这似乎比装箱加倍并使用 StringConvert 更优雅。
    • 但是在这种情况下,您将从数据库中获取所有数据,然后假设您想在 return list.ToList(); 之前对此列表进行一些过滤!!
    • 当您无法访问 SqlFunctions 时,您没有其他选择。但是,我会在查询中使用它:return (from l in db.Customers orderby l.CompanyName select new {Id=l.CustomerID, Name=l.CompanyName}).AsEnumerable().Select(c=&gt; new SelectListItem{Value=c.Id.ToString(), Text = c.Name}).ToList();。这样做只会从 db 中获取 id/name(而不是所有客户属性),并使用 db 上更有效的索引进行排序。
    【解决方案6】:
    var selectList = db.NewsClasses.ToList<NewsClass>().Select(a => new SelectListItem({
        Text = a.ClassName,
        Value = a.ClassId.ToString()
    });
    

    先转换成object,然后toString()就正确了。

    【讨论】:

      【解决方案7】:

      Brian Cauthon 的回答非常棒!只是一点点更新,对于 EF 6,该类已移至另一个命名空间。因此,在 EF 6 之前,您应该包括:

      System.Data.Objects.SqlClient
      

      如果您更新到 EF 6,或者只是使用此版本,请包括:

      System.Data.Entity.SqlServer
      

      通过在 EF6 中包含不正确的命名空间,代码可以正常编译,但会引发运行时错误。我希望这个说明有助于避免一些混乱。

      【讨论】:

      • 我不得不说您的 答案也很出色。我升级到 EF6 并一直在到处寻找 SqlFunctions。您的回答为我指明了正确的方向。我只是补充一点,您还需要对 EntityFramework.SqlServer 的引用(您可能只有对 EntityFramework 的引用)。
      【解决方案8】:

      我在将 MVC 2 应用程序转换为 MVC 3 时遇到了同样的问题,只是为了给这个问题提供另一个(干净的)解决方案,我想发布我所做的......

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

      GetProducers() 只返回生产者的实体集合。 附: SqlFunctions.StringConvert 对我不起作用。

      【讨论】:

        【解决方案9】:

        如果您的“联系人”充当通用列表,我希望以下代码运行良好。

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

        谢谢。

        【讨论】:

          【解决方案10】:

          另一种解决方案:

          c.ContactId + ""
          

          只需添加空字符串,它就会被转换为字符串。

          【讨论】:

          • 返回错误:System.NotSupportedException:无法将类型“System.Int64”转换为类型“System.Object”。 LINQ to Entities 仅支持转换 EDM 基元或枚举类型。
          【解决方案11】:

          使用 MySql,SqlFunctions.StringConvert 对我不起作用。由于我在项目中的 20 多个地方使用了SelectListItem,因此我想要一个能够在不扭曲 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(); }
              }
          }
          

          【讨论】:

            【解决方案12】:

            如果你使用实体框架并且你想让唯一的 int 可以接受,那么你可以在 linq 查询中使用它,你可以试试这个

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

            它会起作用,因为使用 (int) 会将您的值转换为 int,因此您不需要将字符串转换为 int 并且您会得到想要的结果。

            这在我的项目中对我有用,我认为这对你会有所帮助

            【讨论】:

              【解决方案13】:

              我的理解是,您必须创建一个部分类来“扩展”您的模型并添加一个只读属性,该属性可以利用该类的其余属性。

              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 to Entities(在 .NET 3.5 中)中使用自定义属性。
              • 我没有测试它,但它也不会工作。因为它不是表字段属性。我可以先用 ToArray() 然后 linqing 对象,但我想查询数据库。我认为将无法做到这一点。我创建了自己的 ListItem,它采用一个 int 字段。这对我来说效果更好。
              【解决方案14】:
              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&lt;Int32&gt;

              在过去几天的反复试验中,我花了很多时间搜索才能找到这个。

              我希望这对一些程序员有所帮助。

              【讨论】:

              • 对我不起作用。它抛出异常“...System.String Concat(System.Object) 不能被翻译成商店表达式...”。
              • 对我也不起作用。我还收到“System.NotSupportedException:LINQ to Entities 无法识别方法 'System.String Concat(System.Object)' 方法,并且此方法无法转换为存储表达式。”
              • 不起作用 - 使用此答案 [NotSupportedException: LINQ to Entities 无法识别方法 'System.String Concat(System.Object)' 方法,并且此方法无法转换为存储表达式。 ]
              【解决方案15】:

              你可以试试:

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

              【讨论】:

              • 上面的代码将不起作用,因为它会抛出一个错误,说“LINQ to Entities 无法识别方法 'System.String ToString(Int32)' 方法,并且此方法无法转换为存储表达。”
              猜你喜欢
              • 2011-12-26
              • 1970-01-01
              • 2012-05-18
              • 1970-01-01
              • 2015-10-11
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多