【问题标题】:String.Split in a Linq-To-SQL Query?String.Split 在 Linq-To-SQL 查询中?
【发布时间】:2010-11-29 00:26:12
【问题描述】:

我有一个包含这样的 nvarchar 列的数据库表:

1|12.6|18|19

我有一个具有 Decimal[] 属性的业务对象。

我的 LINQ 查询如下所示:

var temp = from r in db.SomeTable select new BusinessObject {
    // Other BusinessObject Properties snipped as they are straight 1:1
    MeterValues = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray()
};
var result = temp.ToArray();

这会引发 NotSupportedException:Method 'System.String[] Split(Char[])' has no supported translation to SQL.

这有点糟糕 :) 有什么方法可以做到这一点,而不必向业务对象添加字符串属性或选择匿名类型然后遍历它?

我目前的“解决方案”是:

var temp = from r in db.SomeTable select new {
    mv = r.MeterValues,
    bo = new BusinessObject { // all the other fields }
};
var result = new List<BusinessObject>();
foreach(var t in temp) {
    var bo = t.bo;
    bo.MeterValues = t.mv.Split('|').Select(Decimal.Parse).ToArray();
    result.Add(bo);
}
return result.ToArray(); // The Method returns BusinessObject[]

不过,这个临时列表有点难看。

我尝试添加 let mv = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray(),但这基本上会导致相同的 NotSupportedException。

如果重要的话,这是 .net 3.5SP1。

【问题讨论】:

    标签: c# .net linq linq-to-sql


    【解决方案1】:

    您需要通过首先调用.AsEnumerable() 来强制select 子句在客户端上运行:

    var result = db.SomeTable.AsEnumerable().Select(r => new BusinessObject {
        ...
        MeterValues = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray()
    }).ToList();
    

    【讨论】:

    • 这是否会选择整个 SomeTable 表?
    • @Michael:是的。无论如何,您都需要选择整个表格。如果您只需要字段的子集,您可以在.AsEnumerable 之前放置一个初始的Select
    • 是的,这并不理想——它基本上会执行“SELECT * FROM SomeTable”。 L2SQL 是否支持 UDF? EF确实(我认为)。如果是这样,您可以在服务器端进行拆分(例如 UDF)
    • @SLaks 抱歉,我认为我的示例不太好,因为我省略了可能有的 where 子句。
    • @Michael:将where 子句放在AsEnumerable 之前。
    【解决方案2】:

    您不能使用拆分,但在这种情况下,您可以执行以下操作:

    // Database value is 1|12.6|18|19
    
    string valueToFind = "19";
    
    var temp = from r in db.SomeTable.Where(r => ("|" + r.MeterValues + "|").Contains("|" + valueToFind + "|"));
    

    此代码在查询中动态地将外部管道 (|) 添加到数据库值,以便您可以对字符串进行开始、中间和结束值匹配。

    例如,上面的代码查找“|19|”在“|1|12.6|18|19|”内,找到并且有效。这适用于任何其他 valueToFind

    【讨论】:

      【解决方案3】:

      您不需要使用临时列表:

      var query = from r in db.SomeTable
                  select new
                  {
                      r.Id,
                      r.Name,
                      r.MeterValues,
                      ...
                  };
      
      var temp = from x in query.AsEnumerable()
                 select new BusinessObject
                 {
                     Id = x.Id,
                     Name = x.Name,
                     MeterValues = x.mv.Split('|').Select(Decimal.Parse).ToArray(),
                     ...
                 };
      
      return temp.ToArray();
      

      【讨论】:

        【解决方案4】:

        不幸的是,您使用的 IQueryable (Linq to SQL) 不支持拆分功能。

        在这种情况下,您实际上只剩下 IEnumerable (Linq to Objects) 支持。你第二个代码 sn-p 是你需要做的,或者类似的......

        var temp = (from r in db.SomeTable select new { 
            mv = r.MeterValues, 
            bo = new BusinessObject { // all the other fields } 
        }).AsEnumerable().Select(blah, blah) ;
        

        【讨论】:

          猜你喜欢
          • 2010-12-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多